From 61e6f920bae4fc76f26ac50e36837ab9bebadc9a Mon Sep 17 00:00:00 2001 From: Florian Fainelli Date: Tue, 7 Feb 2006 16:28:03 +0000 Subject: [PATCH] Added support : SIP, H323, RTSP connection tracking helpers, builded as modules SVN-Revision: 3181 --- openwrt/target/linux/linux-2.4/config/brcm | 6 + .../generic/116-netfilter_nat_sip.patch | 1254 ++++++++++++ .../generic/117-netfilter_nat_h323.patch | 821 ++++++++ .../generic/118-netfilter_nat_rtsp.patch | 1810 +++++++++++++++++ openwrt/target/linux/netfilter.mk | 6 + 5 files changed, 3897 insertions(+) create mode 100644 openwrt/target/linux/linux-2.4/patches/generic/116-netfilter_nat_sip.patch create mode 100644 openwrt/target/linux/linux-2.4/patches/generic/117-netfilter_nat_h323.patch create mode 100644 openwrt/target/linux/linux-2.4/patches/generic/118-netfilter_nat_rtsp.patch diff --git a/openwrt/target/linux/linux-2.4/config/brcm b/openwrt/target/linux/linux-2.4/config/brcm index 0c0823b4ad..a74fbbb7d5 100644 --- a/openwrt/target/linux/linux-2.4/config/brcm +++ b/openwrt/target/linux/linux-2.4/config/brcm @@ -347,6 +347,9 @@ CONFIG_IP_NF_TFTP=m CONFIG_IP_NF_IRC=y CONFIG_IP_NF_CT_PROTO_GRE=m CONFIG_IP_NF_PPTP=m +CONFIG_IP_NF_SIP=m +CONFIG_IP_NF_H323=m +CONFIG_IP_NF_RTSP=m CONFIG_IP_NF_QUEUE=m CONFIG_IP_NF_IPTABLES=y CONFIG_IP_NF_MATCH_LIMIT=m @@ -381,6 +384,9 @@ CONFIG_IP_NF_NAT_NEEDED=y CONFIG_IP_NF_TARGET_MASQUERADE=y CONFIG_IP_NF_TARGET_REDIRECT=m CONFIG_IP_NF_NAT_PPTP=m +CONFIG_IP_NF_NAT_SIP=m +CONFIG_IP_NF_NAT_H323=m +CONFIG_IP_NF_NAT_RTSP=m CONFIG_IP_NF_NAT_PROTO_GRE=m CONFIG_IP_NF_NAT_AMANDA=m CONFIG_IP_NF_NAT_SNMP_BASIC=m diff --git a/openwrt/target/linux/linux-2.4/patches/generic/116-netfilter_nat_sip.patch b/openwrt/target/linux/linux-2.4/patches/generic/116-netfilter_nat_sip.patch new file mode 100644 index 0000000000..e2227b28a1 --- /dev/null +++ b/openwrt/target/linux/linux-2.4/patches/generic/116-netfilter_nat_sip.patch @@ -0,0 +1,1254 @@ +diff -urN linux-2.4.30/net/ipv4/netfilter/Config.in linux-2.4.30.new/net/ipv4/netfilter/Config.in +--- linux-2.4.30/net/ipv4/netfilter/Config.in 2006-02-07 15:38:07.000000000 +0100 ++++ linux-2.4.30.new/net/ipv4/netfilter/Config.in 2006-02-07 15:39:18.000000000 +0100 +@@ -13,6 +13,7 @@ + dep_tristate ' IRC protocol support' CONFIG_IP_NF_IRC $CONFIG_IP_NF_CONNTRACK + dep_tristate ' GRE protocol support' CONFIG_IP_NF_CT_PROTO_GRE $CONFIG_IP_NF_CONNTRACK + dep_tristate ' PPTP protocol support' CONFIG_IP_NF_PPTP $CONFIG_IP_NF_CT_PROTO_GRE ++ dep_tristate ' SIP protocol support' CONFIG_IP_NF_SIP $CONFIG_IP_NF_CONNTRACK + fi + + if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then +@@ -87,6 +88,13 @@ + define_tristate CONFIG_IP_NF_NAT_PROTO_GRE $CONFIG_IP_NF_NAT + fi + fi ++ if [ "$CONFIG_IP_NF_SIP" = "m" ]; then ++ define_tristate CONFIG_IP_NF_NAT_SIP m ++ else ++ if [ "$CONFIG_IP_NF_SIP" = "y" ]; then ++ define_tristate CONFIG_IP_NF_NAT_SIP $CONFIG_IP_NF_NAT ++ fi ++ fi + if [ "$CONFIG_IP_NF_AMANDA" = "m" ]; then + define_tristate CONFIG_IP_NF_NAT_AMANDA m + else +diff -urN linux-2.4.30/net/ipv4/netfilter/ip_conntrack_sip.c linux-2.4.30.new/net/ipv4/netfilter/ip_conntrack_sip.c +--- linux-2.4.30/net/ipv4/netfilter/ip_conntrack_sip.c 1970-01-01 01:00:00.000000000 +0100 ++++ linux-2.4.30.new/net/ipv4/netfilter/ip_conntrack_sip.c 2006-02-07 15:39:18.000000000 +0100 +@@ -0,0 +1,312 @@ ++/* ++ * SIP extension for IP connection tracking. ++ * ++ * Copyright (C) 2004, CyberTAN Corporation ++ * All Rights Reserved. ++ * ++ * THIS SOFTWARE IS OFFERED "AS IS", AND CYBERTAN GRANTS NO WARRANTIES OF ANY ++ * KIND, EXPRESS OR IMPLIED, BY STATUTE, COMMUNICATION OR OTHERWISE. CYBERTAN ++ * SPECIFICALLY DISCLAIMS ANY IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS ++ * FOR A SPECIFIC PURPOSE OR NONINFRINGEMENT CONCERNING THIS SOFTWARE. ++ * ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include ++#include ++#include ++#include ++ ++DECLARE_LOCK(ip_sip_lock); ++ ++struct module *ip_conntrack_sip = THIS_MODULE; ++ ++#define MAX_PORTS 8 ++static int ports[MAX_PORTS]; ++static int ports_c; ++#ifdef MODULE_PARM ++MODULE_PARM(ports, "1-" __MODULE_STRING(MAX_PORTS) "i"); ++#endif ++ ++#if 0 ++ #define DEBUGP printk ++#else ++ #define DEBUGP(format, args...) ++#endif ++ ++#define RTCP_SUPPORT ++ ++static int set_expected_rtp(struct ip_conntrack *ct, u_int32_t dstip, ++ u_int16_t dstport, unsigned int conntype) ++{ ++ struct ip_conntrack_expect expect, *exp = &expect; ++ struct ip_ct_sip_expect *exp_sip_info = &exp->help.exp_sip_info; ++ int ret = 0; ++ ++ memset(&expect, 0, sizeof(expect)); ++ LOCK_BH(&ip_sip_lock); ++ ++ DEBUGP("conntrack_sip: %s: [%s]: DST=%u.%u.%u.%u:%u\n", __FUNCTION__, ++ conntype == CONN_RTP ? "RTP" : "RTCP", NIPQUAD(dstip), dstport); ++ ++ /* exp_sip_info */ ++ exp_sip_info->port = dstport; ++ exp_sip_info->type = conntype; ++ exp_sip_info->nated = 0; ++ ++ /* new expectation */ ++ exp->tuple = ((struct ip_conntrack_tuple) ++ { { 0, { 0 } }, ++ { dstip, { htons(dstport) }, IPPROTO_UDP }}); ++ exp->mask = ((struct ip_conntrack_tuple) ++ { { 0, { 0 } }, ++ { 0xFFFFFFFF, { 0xFFFF }, 0xFFFF }}); ++ exp->expectfn = NULL; ++ ++ if ((ret=ip_conntrack_expect_related(ct, exp)) != 0) { ++ DEBUGP("Can't add new expectation. \n"); ++ } ++ ++ UNLOCK_BH(&ip_sip_lock); ++ ++ return ret; ++} ++ ++/* ++static int unset_expected_rtp(struct ip_conntrack *ct, u_int32_t dstip, u_int16_t dstport) ++{ ++ struct ip_conntrack_expect *exp; ++ const struct ip_conntrack_tuple tuple = { { 0, { 0 } }, ++ { dstip, { htons(dstport) }, IPPROTO_UDP }}; ++ ++ LOCK_BH(&ip_sip_lock); ++ ++ exp = ip_conntrack_expect_find_get(&tuple); ++ if (exp) { ++ DEBUGP("Find the expectation %p, then delete it.\n", exp); ++ ip_conntrack_unexpect_related(exp); ++ } ++ ++ UNLOCK_BH(&ip_sip_lock); ++ ++ return 0; ++}*/ ++ ++/* return: ++ * 0 : Not found ++ * 1 : Found domain name ++ * 2 : Found dotted quads ++ */ ++int find_sdp_rtp_addr(const char *data, size_t dlen, ++ unsigned int *numoff, unsigned int *numlen, u_int32_t *addr) ++{ ++ char *st, *p = (char *)data; ++ const char *limit = data + dlen; ++ unsigned char p1, p2, p3, p4; ++ ++ while (p < limit) { ++ /* find 'c=' line */ ++ if (strncmp(p, "\nc=",3) && strncmp(p, "\rc=",3)) { ++ p++; ++ continue; ++ } ++ p += 3; ++ ++ if (strncmp(p, "IN IP4 ",7)) ++ continue; ++ p += 7; ++ ++ /* IP address */ ++ st = p; ++ ++ /* FQDNs or dotted quads */ ++ while (isalpha(*p) || isdigit(*p) || (*p=='.') || (*p=='-')) { ++ p++; ++ if (p == limit) ++ return 0; ++ } ++ ++ *numoff = st - data; ++ *numlen = p - st; ++ ++ /* Convert the IP address */ ++ p1 = simple_strtoul(st, &st ,10); ++ if (*st != '.') ++ return 1; ++ p2 = simple_strtoul(st+1, &st, 10); ++ if (*st != '.') ++ return 1; ++ p3 = simple_strtoul(st+1, &st, 10); ++ if (*st != '.') ++ return 1; ++ p4 = simple_strtoul(st+1, &st, 10); ++ ++ *addr = (p1<<24) | (p2<<16) | (p3<<8) | p4; ++ ++ return 2; ++ } ++ ++ return 0; ++} ++ ++u_int16_t find_sdp_audio_port(const char *data, size_t dlen, ++ unsigned int *numoff, unsigned int *numlen) ++{ ++ char *st, *p = (char *)data; ++ const char *limit = data + dlen; ++ u_int16_t port = 0; ++ ++ while (p < limit) { ++ /* find 'm=' */ ++ if (strncmp(p, "\nm=", 3) && strncmp(p, "\rm=", 3)) { ++ p++; ++ continue; ++ } ++ p += 3; ++ ++ /* audio stream */ ++ if (strncmp(p ,"audio ",6)) ++ continue; ++ p += 6; ++ ++ st = p; ++ port = simple_strtoul(p, &p, 10); ++ ++ *numoff = st - data; ++ *numlen = p - st; ++ ++ return port; ++ } ++ ++ return 0; ++} ++ ++static int help(const struct iphdr *iph, size_t len, ++ struct ip_conntrack *ct, ++ enum ip_conntrack_info ctinfo) ++{ ++ int dir = CTINFO2DIR(ctinfo); ++ unsigned int matchlen, matchoff; ++ ++ u_int32_t ipaddr=0; ++ u_int16_t port = 0; ++ ++ int found = 0; ++ struct udphdr *udph = (void *)iph + iph->ihl * 4; ++ const char *data = (const char *)udph + 8; ++ unsigned int udplen = len - iph->ihl * 4; ++ unsigned int datalen = udplen - 8; ++ struct ip_ct_sip_master *ct_sip_info = &ct->help.ct_sip_info; ++ ++ DEBUGP("\nconntrack_sip: help(): DIR=%d, conntrackinfo=%u\n", dir, ctinfo); ++ DEBUGP("conntrack_sip: %u.%u.%u.%u:%u -> %u.%u.%u.%u:%u\n", ++ NIPQUAD(ct->tuplehash[dir].tuple.src.ip), ++ ntohs(ct->tuplehash[dir].tuple.src.u.udp.port), ++ NIPQUAD(ct->tuplehash[dir].tuple.dst.ip), ++ ntohs(ct->tuplehash[dir].tuple.dst.u.udp.port) ); ++ ++ /* Reset for a new incoming packet */ ++ ct_sip_info->mangled = 0; ++ ++ /* keep the connection alive */ ++ ip_ct_refresh_acct(ct, ctinfo, iph, (SIP_EXPIRES * HZ)); ++ ++ /* Don't need to set the expectation for upstream direction */ ++ if (dir == IP_CT_DIR_REPLY) ++ return NF_ACCEPT; ++ ++ /* Need to set the expected connection for further incoming RTP stream */ ++ if (strncmp(data, "INVITE", 6) != 0 && strncmp(data, "SIP/2.0 200", 11) != 0) { ++ DEBUGP("conntrack_sip: Not interesting packet.\n"); ++ return NF_ACCEPT; ++ } ++ ++ /* Find RTP address */ ++ found = find_sdp_rtp_addr(data, datalen, &matchoff, &matchlen, &ipaddr); ++ if (!found) ++ return NF_ACCEPT; ++ ++ DEBUGP("conntrack_sip: 'IN IP4' is %s.\n", (found == 1) ? "FQDNs" : "dotted quads"); ++ ++ /* If it's a null address, then the call is on hold */ ++ if (found == 2 && ipaddr == 0) { ++ DEBUGP("conntrack_sip: Null address is found.\n"); ++ return NF_ACCEPT; ++ } ++ ++ /* Find audio port, and we don't like the well-known ports, ++ * which is less than 1024 */ ++ port = find_sdp_audio_port(data, datalen, &matchoff, &matchlen); ++ if (port < 1024) ++ return NF_ACCEPT; ++ ++ DEBUGP("conntrack_sip: audio port=%d.\n", port); ++ ++ ipaddr = ct->tuplehash[dir].tuple.src.ip; ++ ct_sip_info->rtpport = port; ++ ++ /* RFC1889 - RTP uses an even port number and the corresponding RTCP ++ * stream uses the next higher (odd) port number. */ ++ if (set_expected_rtp(ct, ipaddr, port, CONN_RTP) == 0) { ++#ifdef RTCP_SUPPORT ++ set_expected_rtp(ct, ipaddr, port + 1, CONN_RTCP); ++#endif ++ } ++ ++ return NF_ACCEPT; ++} ++ ++static struct ip_conntrack_helper sip[MAX_PORTS]; ++ ++ ++/* Not __exit: called from init() */ ++static void fini(void) ++{ ++ int i; ++ for (i = 0; (i < MAX_PORTS) && ports[i]; i++) { ++ DEBUGP("ip_ct_sip: unregistering helper for port %d\n", ++ ports[i]); ++ ip_conntrack_helper_unregister(&sip[i]); ++ } ++} ++ ++static int __init init(void) ++{ ++ int i, ret; ++ ++ if (ports[0] == 0) ++ ports[0] = SIP_PORT; ++ ++ for (i = 0; (i < MAX_PORTS) && ports[i]; i++) { ++ memset(&sip[i], 0, sizeof(struct ip_conntrack_helper)); ++ sip[i].tuple.dst.u.udp.port = htons(ports[i]); ++ sip[i].tuple.dst.protonum = IPPROTO_UDP; ++ sip[i].mask.dst.u.udp.port = 0xF0FF; ++ sip[i].mask.dst.protonum = 0xFFFF; ++ sip[i].help = help; ++ sip[i].timeout = RTP_TIMEOUT; ++ DEBUGP("ip_ct_sip: registering helper for port %d\n", ++ ports[i]); ++ ret = ip_conntrack_helper_register(&sip[i]); ++ ++ if (ret) { ++ fini(); ++ return ret; ++ } ++ ports_c++; ++ } ++ return 0; ++} ++ ++ ++EXPORT_SYMBOL(ip_sip_lock); ++EXPORT_SYMBOL(ip_conntrack_sip); ++ ++module_init(init); ++module_exit(fini); +diff -urN linux-2.4.30/net/ipv4/netfilter/ip_nat_sip.c linux-2.4.30.new/net/ipv4/netfilter/ip_nat_sip.c +--- linux-2.4.30/net/ipv4/netfilter/ip_nat_sip.c 1970-01-01 01:00:00.000000000 +0100 ++++ linux-2.4.30.new/net/ipv4/netfilter/ip_nat_sip.c 2006-02-07 15:39:18.000000000 +0100 +@@ -0,0 +1,800 @@ ++/* ++ * SIP extension for TCP NAT alteration. ++ * ++ * Copyright (C) 2004, CyberTAN Corporation ++ * All Rights Reserved. ++ * ++ * THIS SOFTWARE IS OFFERED "AS IS", AND CYBERTAN GRANTS NO WARRANTIES OF ANY ++ * KIND, EXPRESS OR IMPLIED, BY STATUTE, COMMUNICATION OR OTHERWISE. CYBERTAN ++ * SPECIFICALLY DISCLAIMS ANY IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS ++ * FOR A SPECIFIC PURPOSE OR NONINFRINGEMENT CONCERNING THIS SOFTWARE. ++ * ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#if 0 ++ #define DEBUGP printk ++#else ++ #define DEBUGP(format, args...) ++#endif ++ ++#define MAX_PORTS 8 ++static int ports[MAX_PORTS]; ++static int ports_c = 0; ++ ++#ifdef MODULE_PARM ++MODULE_PARM(ports, "1-" __MODULE_STRING(MAX_PORTS) "i"); ++#endif ++ ++DECLARE_LOCK_EXTERN(ip_sip_lock); ++ ++#define RTCP_SUPPORT ++ ++/* down(stream): caller -> callee ++ up(stream): caller <- callee */ ++ ++ ++/* Return 1 for match, 0 for accept, -1 for partial. */ ++static int find_pattern(const char *data, size_t dlen, ++ const char *pattern, size_t plen, ++ char skip, char term, ++ unsigned int *numoff, ++ unsigned int *numlen ++ ) ++{ ++ size_t i, j, k; ++ ++// DEBUGP("find_pattern `%s': dlen = %u\n", pattern, dlen); ++ if (dlen == 0) ++ return 0; ++ ++ if (dlen <= plen) { ++ /* Short packet: try for partial? */ ++ if (strnicmp(data, pattern, dlen) == 0) ++ return -1; ++ else return 0; ++ } ++ ++ for(i=0; i<= (dlen - plen); i++){ ++ if( memcmp(data + i, pattern, plen ) != 0 ) continue; ++ ++ /* patten match !! */ ++ *numoff=i + plen; ++ for (j=*numoff, k=0; data[j] != term; j++, k++) ++ if( j > dlen ) return -1 ; /* no terminal char */ ++ ++ *numlen = k; ++ return 1; ++ } ++ ++ return 0; ++} ++ ++static unsigned int ++sip_nat_expected(struct sk_buff **pskb, ++ unsigned int hooknum, ++ struct ip_conntrack *ct, ++ struct ip_nat_info *info) ++{ ++ struct ip_nat_multi_range mr; ++ u_int32_t newdstip, newsrcip, newip; ++ struct ip_ct_sip_expect *exp_sip_info; ++ struct ip_conntrack *master = master_ct(ct); ++ ++ IP_NF_ASSERT(info); ++ IP_NF_ASSERT(master); ++ IP_NF_ASSERT(!(info->initialized & (1<master->help.exp_sip_info; ++ ++ LOCK_BH(&ip_sip_lock); ++ ++ /* Outer machine IP */ ++ newsrcip = ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple.src.ip; ++ /* Client (virtual) IP under NAT */ ++ newdstip = master->tuplehash[IP_CT_DIR_ORIGINAL].tuple.src.ip; ++ ++ UNLOCK_BH(&ip_sip_lock); ++ ++ if (HOOK2MANIP(hooknum) == IP_NAT_MANIP_SRC) ++ newip = newsrcip; ++ else ++ newip = newdstip; ++ ++ DEBUGP("sip_nat_expected: IP to %u.%u.%u.%u:%u\n", NIPQUAD(newip), ++ htons(exp_sip_info->port)); ++ ++ mr.rangesize = 1; ++ /* We don't want to manip the per-protocol, just the IPs... */ ++ mr.range[0].flags = IP_NAT_RANGE_MAP_IPS; ++ mr.range[0].min_ip = mr.range[0].max_ip = newip; ++ ++ /* ... unless we're doing a MANIP_DST, in which case, make ++ sure we map to the correct port */ ++ if (HOOK2MANIP(hooknum) == IP_NAT_MANIP_DST) { ++ mr.range[0].flags |= IP_NAT_RANGE_PROTO_SPECIFIED; ++ mr.range[0].min = mr.range[0].max ++ = ((union ip_conntrack_manip_proto) ++ { htons(exp_sip_info->port) }); ++ } ++ ++ return ip_nat_setup_info(ct, &mr, hooknum); ++} ++ ++static int _find_sip_via_addrport(const char *data, size_t dlen, ++ unsigned int *numoff, unsigned int *numlen) ++{ ++ const char *addr, *p = data; ++ const char *limit = data + dlen; ++ ++ while (p < limit) { ++ /* Find the topmost via tag */ ++ if (strnicmp(p, "\nvia:",5) && strnicmp(p, "\nv:",3) && ++ strnicmp(p, "\rvia:",5) && strnicmp(p, "\rv:",3)) { ++ p++; ++ continue; ++ } ++ ++ /* Look for UDP */ ++ while (*p!='U' && *p!='u') { ++ if (p == limit) ++ return 0; ++ p++; ++ } ++ p+= 3; ++ ++ if (p >= limit) ++ return 0; ++ ++ /* Skip a space */ ++ while (*p == ' '){ ++ if (p == limit) ++ return 0; ++ p++; ++ } ++ ++ /* IP address */ ++ addr = p; ++ ++ /* FQDNs or dotted quads */ ++ while (isalpha(*p) || isdigit(*p) || (*p=='.') || (*p=='-')) { ++ p++; ++ if (p == limit) ++ return 0; ++ } ++ ++ /* If there is a port number, skip it */ ++ if (*p == ':') { ++ p++; ++ if (p == limit) ++ return 0; ++ ++ while (isdigit(*p)) { ++ p++; ++ if (p == limit) ++ return 0; ++ } ++ } ++ ++ *numoff = addr - data; ++ *numlen = p - addr; ++ ++ return 1; ++ } ++ ++ return 0; /* Not found */ ++} ++ ++static int _mangle_sip_via(struct ip_conntrack *ct, enum ip_conntrack_info ctinfo, ++ struct sk_buff **pskb, u_int32_t newip, u_int16_t newport, ++ unsigned int numoff, unsigned int numlen) ++{ ++ int buflen; ++ char buffer[sizeof("nnn.nnn.nnn.nnn:nnnnn")]; ++ ++ sprintf(buffer, "%u.%u.%u.%u:%u", NIPQUAD(newip), newport); ++ buflen = strlen(buffer); ++ ++ MUST_BE_LOCKED(&ip_sip_lock); ++ ++ if (!ip_nat_mangle_udp_packet(pskb, ct, ctinfo, numoff, ++ numlen, buffer, buflen) ) ++ return 0; ++ ++ DEBUGP("(SIP) Via is changed to %s.\n", buffer); ++ ++ return buflen - numlen; ++} ++ ++static int mangle_sip_via(struct ip_conntrack *ct, enum ip_conntrack_info ctinfo, ++ struct sk_buff **pskb, u_int32_t newip, u_int16_t newport) ++{ ++ struct iphdr *iph = (*pskb)->nh.iph; ++ struct udphdr *udph = (void *)iph + iph->ihl * 4; ++ const char *data = (const char *)udph + 8; ++ unsigned int udplen = ntohs(iph->tot_len) - (iph->ihl * 4); ++ unsigned int datalen = udplen - 8; ++ unsigned int matchoff, matchlen; ++ ++ /* Find the topmost via tag */ ++ _find_sip_via_addrport(data , datalen, &matchoff, &matchlen); ++ return _mangle_sip_via(ct, ctinfo, pskb, newip, newport, ++ matchoff, matchlen); ++} ++ ++static int mangle_sip_contact(struct ip_conntrack *ct, enum ip_conntrack_info ctinfo, ++ struct sk_buff **pskb, u_int32_t newip, u_int16_t newport) ++{ ++ struct iphdr *iph = (*pskb)->nh.iph; ++ struct udphdr *udph = (void *)iph + iph->ihl * 4; ++ const char *data = (const char *)udph + 8; ++ unsigned int udplen = ntohs(iph->tot_len) - (iph->ihl * 4); ++ unsigned int datalen = udplen - 8; ++ ++ int buflen, diff_len = 0; ++ char buffer[sizeof("nnn.nnn.nnn.nnn:nnnnn")]; ++ const char *uri, *addr, *p = data; ++ const char *limit = data + datalen; ++ ++ ++ while (p < limit) { ++ if (strnicmp(p, "\ncontact:", 9) && strnicmp(p, "\nm:", 3) && ++ strnicmp(p, "\rcontact:", 9) && strnicmp(p, "\rm:", 3)) { ++ p++; ++ continue; ++ } ++ ++ while (strnicmp(p, "sip:", 4)) { ++ if (p == limit) ++ return 0; ++ p++; ++ } ++ p += 4; ++ ++ /* If there is user info in the contact */ ++ uri = p; ++ ++ while (*p!='@' && *p!='>' && *p!=';' && *p!='\n' && *p!='\r' && *p!='?' && *p!=',') { ++ if (p == limit) ++ return 0; ++ p++; ++ } ++ ++ if (*p=='@') ++ p++; ++ else ++ p = uri; /* back to previous URI pointer */ ++ ++ /* IP address */ ++ addr = p; ++ ++ /* FQDNs or dotted quads */ ++ while (isalpha(*p) || isdigit(*p) || (*p=='.') || (*p=='-')) { ++ p++; ++ if (p == limit) ++ return 0; ++ } ++ ++ /* If there is a port number, skip it */ ++ if (*p==':') { ++ p++; ++ while (isdigit(*p)) ++ p++; ++ } ++ ++ sprintf(buffer, "%u.%u.%u.%u:%u", NIPQUAD(newip), newport); ++ buflen = strlen(buffer); ++ ++ MUST_BE_LOCKED(&ip_sip_lock); ++ ++ if (!ip_nat_mangle_udp_packet(pskb, ct, ctinfo, addr - data, ++ p - addr, buffer, buflen) ) ++ return 0; ++ ++ diff_len = buflen - (p - addr); ++ DEBUGP("(SIP) Contact is changed to %s.\n", buffer); ++ break; ++ } ++ ++ return diff_len; ++} ++ ++static int _find_sip_content_length_size(const char *data, size_t dlen, ++ unsigned int *numoff, unsigned int *numlen) ++{ ++ char *st, *p = (char *)data; ++ const char *limit = data + dlen; ++ int size = 0; ++ ++ while (p < limit) { ++ if (strnicmp(p, "\nContent-Length:", 16) && strnicmp(p, "\nl:", 3) && ++ strnicmp(p, "\rContent-Length:", 16) && strnicmp(p, "\rm:", 3)) { ++ p++; ++ continue; ++ } ++ ++ /* Go through the string above */ ++ while (*p != ':') { ++ if (p == limit) ++ return 0; ++ p++; ++ } ++ p++; ++ ++ while (*p == ' ') { ++ if (p == limit) ++ return 0; ++ p++; ++ } ++ ++ st = p; ++ size = simple_strtoul(p, &p, 10); ++ ++ *numoff = st - data; ++ *numlen = p - st; ++ ++ return size; ++ } ++ ++ return 0; ++} ++ ++static int mangle_sip_content_length(struct ip_conntrack *ct, enum ip_conntrack_info ctinfo, ++ struct sk_buff **pskb, int diff_len) ++{ ++ struct iphdr *iph = (*pskb)->nh.iph; ++ struct udphdr *udph = (void *)iph + iph->ihl * 4; ++ const char *data = (const char *)udph + 8; ++ unsigned int udplen = ntohs(iph->tot_len) - (iph->ihl * 4); ++ unsigned int datalen = udplen - 8; ++ ++ unsigned int matchlen, matchoff; ++ int size, buflen; ++ char buffer[sizeof("nnnnn")]; ++ ++ /* original legth */ ++ size = _find_sip_content_length_size(data, datalen, &matchoff, &matchlen); ++ ++ /* new legth */ ++ sprintf(buffer, "%u", size + diff_len); ++ buflen = strlen(buffer); ++ ++ if (!ip_nat_mangle_udp_packet(pskb, ct, ctinfo, matchoff, ++ matchlen, buffer, buflen) ) ++ return 0; ++ ++ DEBUGP("(SDP) Content-Length is changed %d->%s.\n", size, buffer); ++ return buflen - matchlen; ++ ++} ++ ++static int mangle_sip_sdp_content(struct ip_conntrack *ct, enum ip_conntrack_info ctinfo, ++ struct sk_buff **pskb, u_int32_t newip, u_int16_t newport) ++{ ++ struct iphdr *iph = (*pskb)->nh.iph; ++ struct udphdr *udph = (void *)iph + iph->ihl * 4; ++ const char *data = (const char *)udph + 8; ++ unsigned int udplen = ntohs(iph->tot_len) - (iph->ihl * 4); ++ unsigned int datalen = udplen - 8; ++ ++ unsigned int matchlen, matchoff; ++ int found, buflen, diff_len = 0; ++ char buffer[sizeof("nnn.nnn.nnn.nnn")]; ++ char *addr, *p; ++ char *limit = (char *)data + datalen; ++ u_int32_t ipaddr = 0; ++ u_int16_t getport; ++ int dir; ++ ++ /* Find RTP address */ ++ found = find_sdp_rtp_addr(data, datalen, &matchoff, &matchlen, &ipaddr); ++ if (found) { ++ /* If it's a null address, then the call is on hold */ ++ if (found == 2 && ipaddr == 0) ++ return 0; ++ ++ sprintf(buffer, "%u.%u.%u.%u", NIPQUAD(newip)); ++ buflen = strlen(buffer); ++ ++ MUST_BE_LOCKED(&ip_sip_lock); ++ ++ if (!ip_nat_mangle_udp_packet(pskb, ct, ctinfo, matchoff, ++ matchlen, buffer, buflen) ) ++ return 0; ++ ++ diff_len += (buflen - matchlen); ++ DEBUGP("(SDP) RTP address is changed to %s.\n", buffer); ++ } ++ ++ /* Find audio port */ ++ getport = find_sdp_audio_port(data, datalen, &matchoff, &matchlen); ++ if (getport != newport) { ++ sprintf(buffer, "%d", newport); ++ buflen = strlen(buffer); ++ ++ MUST_BE_LOCKED(&ip_sip_lock); ++ ++ if (!ip_nat_mangle_udp_packet(pskb, ct, ctinfo, matchoff, ++ matchlen, buffer, buflen) ) ++ return 0; ++ ++ diff_len += (buflen - matchlen); ++ DEBUGP("(SDP) audio port is changed to %d.\n", newport); ++ } ++ ++ dir = CTINFO2DIR(ctinfo); ++ if (dir == IP_CT_DIR_ORIGINAL) ++ return diff_len; ++ ++ /* Find Session ID address */ ++ found = find_pattern(data, datalen, " IN IP4 ", 8, ' ', '\r', ++ &matchoff, &matchlen); ++ if (found) { ++ p = addr = (char *)data + matchoff; ++ ++ /* FQDNs or dotted quads */ ++ while (isalpha(*p) || isdigit(*p) || (*p=='.') || (*p=='-')) { ++ p++; ++ if (p == limit) ++ return 0; ++ } ++ ++ sprintf(buffer, "%u.%u.%u.%u", NIPQUAD(newip)); ++ buflen = strlen(buffer); ++ ++ MUST_BE_LOCKED(&ip_sip_lock); ++ ++ if (!ip_nat_mangle_udp_packet(pskb, ct, ctinfo, addr - data, ++ p - addr, buffer, buflen) ) ++ return 0; ++ ++ diff_len += (buflen - (p - addr)); ++ DEBUGP("(SDP) Session ID is changed to %s.\n", buffer); ++ } ++ ++ return diff_len; ++} ++ ++static int mangle_sip_packet(struct ip_conntrack *ct, enum ip_conntrack_info ctinfo, ++ struct sk_buff **pskb, u_int32_t newip) ++{ ++ struct iphdr *iph = (*pskb)->nh.iph; ++ struct udphdr *udph = (void *)iph + iph->ihl * 4; ++ const char *data = (const char *)udph + 8; ++ int diff_len = 0; ++ struct ip_ct_sip_master *ct_sip_info = &ct->help.ct_sip_info; ++ u_int16_t natport = ntohs(ct->tuplehash[IP_CT_DIR_REPLY].tuple.dst.u.udp.port); ++ ++ DEBUGP("nat_sip: %s:(%d)\n", __FUNCTION__, __LINE__); ++ ++ ct_sip_info->mangled = 1; ++ ++ /* Changes the via, if this is a request */ ++ if (strnicmp(data,"SIP/2.0",7) != 0) { ++ mangle_sip_via(ct, ctinfo, pskb, newip, natport); ++ } ++ ++ mangle_sip_contact(ct, ctinfo, pskb, newip, natport); ++ ++ if ((diff_len = mangle_sip_sdp_content(ct, ctinfo, pskb, newip, ct_sip_info->rtpport)) != 0) ++ mangle_sip_content_length(ct, ctinfo, pskb, diff_len); ++ ++ return 1; ++} ++ ++static struct ip_conntrack_expect * ++expect_find(struct ip_conntrack *ct, u_int32_t dstip, u_int16_t dstport) ++{ ++ const struct ip_conntrack_tuple tuple = { { 0, { 0 } }, ++ { dstip, { htons(dstport) }, IPPROTO_UDP }}; ++ ++ return ip_conntrack_expect_find_get(&tuple); ++ ++} ++ ++static int sip_out_data_fixup(struct ip_conntrack *ct, ++ struct sk_buff **pskb, ++ enum ip_conntrack_info ctinfo, ++ struct ip_conntrack_expect *expect) ++{ ++ struct ip_conntrack_tuple newtuple; ++ struct ip_ct_sip_master *ct_sip_info = &ct->help.ct_sip_info; ++ struct ip_ct_sip_expect *exp_sip_info; ++ u_int32_t wanip = ct->tuplehash[IP_CT_DIR_REPLY].tuple.dst.ip; // NAT wan ip ++ u_int16_t port = 0; ++#ifdef RTCP_SUPPORT ++ struct ip_conntrack_expect *rtcp_exp; ++#endif ++ ++ MUST_BE_LOCKED(&ip_sip_lock); ++ ++ if (expect) { ++ DEBUGP("nat_sip: %s: There is a exp %p.\n", __FUNCTION__, expect); ++ ++ exp_sip_info = &expect->help.exp_sip_info; ++ if (exp_sip_info->nated) { ++ DEBUGP("nat_sip: %s: The exp %p had been changed.\n", __FUNCTION__, expect); ++ goto mangle; ++ } ++ ++ /* RTP expect */ ++ if (exp_sip_info->type == CONN_RTP) { ++ port = ntohs(expect->tuple.dst.u.udp.port); ++#ifdef RTCP_SUPPORT ++ rtcp_exp = expect_find(ct, expect->tuple.dst.ip, port + 1); ++#endif ++ /* RFC1889 - If an application is supplied with an odd number ++ * for use as the RTP port, it should replace this number with ++ * the next lower (even) number. */ ++ if (port % 2) ++ port++; ++ ++ /* fullfill newtuple */ ++ newtuple.dst.ip = wanip; ++ newtuple.src.ip = expect->tuple.src.ip; ++ newtuple.dst.protonum = expect->tuple.dst.protonum; ++ ++ /* Try to get same port: if not, try to change it. */ ++ for (; port != 0; port += 2) { ++ newtuple.dst.u.udp.port = htons(port); ++ if (ip_conntrack_change_expect(expect, &newtuple) == 0) { ++#ifdef RTCP_SUPPORT ++ /* Change RTCP */ ++ if (rtcp_exp) { ++ DEBUGP("nat_sip: %s: RTCP exp %p found.\n", ++ __FUNCTION__, rtcp_exp); ++ newtuple.dst.u.udp.port = htons(port + 1); ++ if (ip_conntrack_change_expect(rtcp_exp, &newtuple) != 0) { ++ DEBUGP("nat_sip: %s: Can't change RTCP exp %p.\n", ++ __FUNCTION__, rtcp_exp); ++ continue; ++ } ++ rtcp_exp->help.exp_sip_info.nated = 1; ++ } ++#endif ++ break; ++ } ++ } ++ if (port == 0) ++ return 0; ++ ++ exp_sip_info->nated = 1; ++ ct_sip_info->rtpport = port; ++ DEBUGP("nat_sip: %s: RTP exp %p, masq port=%d\n", __FUNCTION__, expect, port); ++ } ++#ifdef RTCP_SUPPORT ++ else { ++ /* We ignore the RTCP expect, and will adjust it later ++ * during RTP expect */ ++ DEBUGP("nat_sip: %s: RTCP exp %p, by-pass.\n", __FUNCTION__, expect); ++ return 1; ++ } ++#endif ++ } ++ ++mangle: ++ /* Change address inside packet to match way we're mapping ++ this connection. */ ++ if (!ct_sip_info->mangled) ++ if (!mangle_sip_packet(ct, ctinfo, pskb, wanip)) ++ return 0; ++ ++ return 1; ++} ++ ++static int sip_in_data_fixup(struct ip_conntrack *ct, ++ struct sk_buff **pskb, ++ enum ip_conntrack_info ctinfo, ++ struct ip_conntrack_expect *expect) ++{ ++ struct iphdr *iph = (*pskb)->nh.iph; ++ struct udphdr *udph = (void *)iph + iph->ihl * 4; ++ const char *data = (const char *)udph + 8; ++ unsigned int udplen = ntohs(iph->tot_len) - (iph->ihl * 4); ++ unsigned int datalen = udplen - 8; ++ struct ip_ct_sip_master *ct_sip_info = &ct->help.ct_sip_info; ++ u_int32_t wanip = ct->tuplehash[IP_CT_DIR_REPLY].tuple.dst.ip; // NAT wan ip ++ unsigned int matchlen, matchoff; ++ int found, diff_len = 0; ++ u_int32_t ipaddr = 0, vip = 0; ++ u_int16_t port = 0, vport = 0, aport = 0; ++ struct ip_conntrack_expect *exp; ++#ifdef RTCP_SUPPORT ++ struct ip_conntrack_expect *rtcpexp; ++#endif ++ ++ if (expect) ++ DEBUGP("nat_sip: %s: There is a exp %p.\n", __FUNCTION__, expect); ++ ++ /* Prevent from mangling the packet or expect twice */ ++ if (ct_sip_info->mangled) ++ return 1; ++ ++ ct_sip_info->mangled = 1; ++ ++ if (strnicmp(data, "SIP/2.0 200", 11) == 0) { ++ /* Find CSeq field */ ++ found = find_pattern(data, datalen, "CSeq: ", 6, ' ', '\r', ++ &matchoff, &matchlen); ++ if (found) { ++ char *p = (char *)data + matchoff; ++ ++ simple_strtoul(p, &p, 10); ++ if (strnicmp(p, " REGISTER", 9) == 0) { ++ DEBUGP("nat_sip: 200 OK - REGISTER\n"); ++ vip = ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple.src.ip; ++ vport = ntohs(ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple.src.u.udp.port); ++ mangle_sip_via(ct, ctinfo, pskb, vip, vport); ++ mangle_sip_contact(ct, ctinfo, pskb, vip, vport); ++ return 1; ++ } ++ } ++ } ++ ++ /* Only interesting the SDP content. */ ++ if (strnicmp(data, "INVITE", 6) != 0 && strnicmp(data, "SIP/2.0 200", 11) != 0) ++ return 1; ++ ++ /* Find RTP address */ ++ found = find_sdp_rtp_addr(data, datalen, &matchoff, &matchlen, &ipaddr); ++ ++ DEBUGP("nat_sip: sdp address found = %d, ipaddr = %u.\n", found, ipaddr); ++ if (found < 2) ++ return 1; ++ ++ /* Is it a null address or our WAN address? */ ++ if (ipaddr == 0 || (htonl(ipaddr) != wanip)) ++ return 1; ++ ++ DEBUGP("nat_sip: %s: This is a lookback RTP connection.\n", __FUNCTION__); ++ ++ /* Find audio port, and we don't like the well-known ports, ++ * which is less than 1024 */ ++ port = find_sdp_audio_port(data, datalen, &matchoff, &matchlen); ++ if (port < 1024) ++ return 0; ++ ++ exp = expect_find(ct, wanip, port); ++ if (exp) { ++ DEBUGP("nat_sip: %s: Found exp %p, tuple.dst=%u.%u.%u.%u:%u.\n", ++ __FUNCTION__, exp, NIPQUAD(ipaddr), port); ++ ++ /* Restore masq-ed SDP */ ++ vip = exp->expectant->tuplehash[IP_CT_DIR_ORIGINAL].tuple.src.ip; ++ aport = exp->help.exp_sip_info.port; ++ if ((diff_len = mangle_sip_sdp_content(ct, ctinfo, pskb, vip, aport)) != 0) ++ mangle_sip_content_length(ct, ctinfo, pskb, diff_len); ++ ++ /* Unset RTP, RTCP expect, respectively */ ++ ip_conntrack_unexpect_related(exp); ++#ifdef RTCP_SUPPORT ++ rtcpexp = expect_find(ct, wanip, port + 1); ++ if (rtcpexp) ++ ip_conntrack_unexpect_related(rtcpexp); ++#endif ++ } ++ ++ return 1; ++} ++ ++static unsigned int nat_help(struct ip_conntrack *ct, ++ struct ip_conntrack_expect *exp, ++ struct ip_nat_info *info, ++ enum ip_conntrack_info ctinfo, ++ unsigned int hooknum, ++ struct sk_buff **pskb) ++{ ++ int dir; ++ struct iphdr *iph = (*pskb)->nh.iph; ++ struct udphdr *udph = (void *)iph + iph->ihl * 4; ++ const char *data = (const char *)udph + 8; ++ ++ /* Only mangle things once: original direction in POST_ROUTING ++ and reply direction on PRE_ROUTING. */ ++ dir = CTINFO2DIR(ctinfo); ++ if (!((hooknum == NF_IP_POST_ROUTING && dir == IP_CT_DIR_ORIGINAL) ++ || (hooknum == NF_IP_PRE_ROUTING && dir == IP_CT_DIR_REPLY))) { ++ DEBUGP("nat_sip: Not touching dir %s at hook %s\n", ++ dir == IP_CT_DIR_ORIGINAL ? "ORIG" : "REPLY", ++ hooknum == NF_IP_POST_ROUTING ? "POSTROUTING" ++ : hooknum == NF_IP_PRE_ROUTING ? "PREROUTING" ++ : hooknum == NF_IP_LOCAL_OUT ? "OUTPUT" : "???"); ++ return NF_ACCEPT; ++ } ++ ++ if (strnicmp(data, "REGISTER" , 8) == 0) ++ DEBUGP("nat_sip: REGISTER\n"); ++ else if (strnicmp(data, "INVITE" , 6) == 0) ++ DEBUGP("nat_sip: INVITE\n"); ++ else if (strnicmp(data, "ACK" , 3) == 0) ++ DEBUGP("nat_sip: ACK\n"); ++ else if (strnicmp(data, "BYE", 3) == 0) ++ DEBUGP("nat_sip: BYE\n"); ++ else if (strnicmp(data, "SIP/2.0 200", 11) == 0) ++ DEBUGP("nat_sip: 200 OK\n"); ++ else if (strnicmp(data, "SIP/2.0 100", 11) == 0) ++ DEBUGP("nat_sip: 100 Trying\n"); ++ else if (strnicmp(data, "SIP/2.0 180", 11) == 0) ++ DEBUGP("nat_sip: 180 Ringing\n"); ++ ++ LOCK_BH(&ip_sip_lock); ++ ++ if (dir == IP_CT_DIR_ORIGINAL) ++ sip_out_data_fixup(ct, pskb, ctinfo, exp); ++ else ++ sip_in_data_fixup(ct, pskb, ctinfo, exp); ++ ++ UNLOCK_BH(&ip_sip_lock); ++ ++ return NF_ACCEPT; ++} ++ ++static struct ip_nat_helper sip[MAX_PORTS]; ++static char sip_names[MAX_PORTS][6]; ++ ++/* Not __exit: called from init() */ ++static void fini(void) ++{ ++ int i; ++ ++ for (i = 0; (i < MAX_PORTS) && ports[i]; i++) { ++ DEBUGP("ip_nat_sip: unregistering port %d\n", ports[i]); ++ ip_nat_helper_unregister(&sip[i]); ++ } ++} ++ ++static int __init init(void) ++{ ++ int i, ret=0; ++ char *tmpname; ++ ++ if (ports[0] == 0) ++ ports[0] = SIP_PORT; ++ ++ for (i = 0; (i < MAX_PORTS) && ports[i]; i++) { ++ ++ memset(&sip[i], 0, sizeof(struct ip_nat_helper)); ++ ++ sip[i].tuple.dst.u.udp.port = htons(ports[i]); ++ sip[i].tuple.dst.protonum = IPPROTO_UDP; ++ sip[i].mask.dst.u.udp.port = 0xF0FF; ++ sip[i].mask.dst.protonum = 0xFFFF; ++ sip[i].help = nat_help; ++ sip[i].expect = sip_nat_expected; ++ sip[i].flags = IP_NAT_HELPER_F_ALWAYS; ++ ++ tmpname = &sip_names[i][0]; ++ sprintf(tmpname, "sip%2.2d", i); ++ sip[i].name = tmpname; ++ ++ DEBUGP("ip_nat_sip: Trying to register for port %d\n", ++ ports[i]); ++ ret = ip_nat_helper_register(&sip[i]); ++ ++ if (ret) { ++ printk("ip_nat_sip: error registering " ++ "helper for port %d\n", ports[i]); ++ fini(); ++ return ret; ++ } ++ ports_c++; ++ } ++ ++ return ret; ++} ++ ++module_init(init); ++module_exit(fini); +diff -urN linux-2.4.30/net/ipv4/netfilter/Makefile linux-2.4.30.new/net/ipv4/netfilter/Makefile +--- linux-2.4.30/net/ipv4/netfilter/Makefile 2006-02-07 15:38:07.000000000 +0100 ++++ linux-2.4.30.new/net/ipv4/netfilter/Makefile 2006-02-07 15:39:18.000000000 +0100 +@@ -53,6 +53,10 @@ + ifdef CONFIG_IP_NF_NAT_PPTP + export-objs += ip_conntrack_pptp.o + endif ++obj-$(CONFIG_IP_NF_SIP) += ip_conntrack_sip.o ++ifdef CONFIG_IP_NF_NAT_SIP ++ export-objs += ip_conntrack_sip.o ++endif + + + # NAT helpers +@@ -62,6 +66,7 @@ + obj-$(CONFIG_IP_NF_NAT_IRC) += ip_nat_irc.o + obj-$(CONFIG_IP_NF_NAT_PROTO_GRE) += ip_nat_proto_gre.o + obj-$(CONFIG_IP_NF_NAT_PPTP) += ip_nat_pptp.o ++obj-$(CONFIG_IP_NF_NAT_SIP) += ip_nat_sip.o + + # generic IP tables + obj-$(CONFIG_IP_NF_IPTABLES) += ip_tables.o +diff -urN linux-2.4.30/include/linux/netfilter_ipv4/ip_conntrack.h linux-2.4.30.new/include/linux/netfilter_ipv4/ip_conntrack.h +--- linux-2.4.30/include/linux/netfilter_ipv4/ip_conntrack.h 2006-02-07 15:38:07.000000000 +0100 ++++ linux-2.4.30.new/include/linux/netfilter_ipv4/ip_conntrack.h 2006-02-07 15:39:18.000000000 +0100 +@@ -71,6 +71,7 @@ + #include + #include + #include ++#include + + /* per expectation: application helper private data */ + union ip_conntrack_expect_help { +@@ -79,6 +80,7 @@ + struct ip_ct_ftp_expect exp_ftp_info; + struct ip_ct_irc_expect exp_irc_info; + struct ip_ct_pptp_expect exp_pptp_info; ++ struct ip_ct_sip_expect exp_sip_info; + + #ifdef CONFIG_IP_NF_NAT_NEEDED + union { +@@ -93,6 +95,7 @@ + struct ip_ct_ftp_master ct_ftp_info; + struct ip_ct_irc_master ct_irc_info; + struct ip_ct_pptp_master ct_pptp_info; ++ struct ip_ct_sip_master ct_sip_info; + }; + + #ifdef CONFIG_IP_NF_NAT_NEEDED +diff -urN linux-2.4.30/include/linux/netfilter_ipv4/ip_conntrack_sip.h linux-2.4.30.new/include/linux/netfilter_ipv4/ip_conntrack_sip.h +--- linux-2.4.30/include/linux/netfilter_ipv4/ip_conntrack_sip.h 1970-01-01 01:00:00.000000000 +0100 ++++ linux-2.4.30.new/include/linux/netfilter_ipv4/ip_conntrack_sip.h 2006-02-07 15:39:18.000000000 +0100 +@@ -0,0 +1,56 @@ ++#ifndef _IP_CONNTRACK_SIP_H ++#define _IP_CONNTRACK_SIP_H ++/* SIP tracking. */ ++ ++#ifdef __KERNEL__ ++ ++#include ++ ++/* Protects sip part of conntracks */ ++DECLARE_LOCK_EXTERN(ip_sip_lock); ++ ++#define SIP_PORT 5060 /* UDP */ ++#define SIP_EXPIRES 3600 /* seconds */ ++#define RTP_TIMEOUT 180 /* seconds */ ++ ++#endif /* __KERNEL__ */ ++ ++/* SIP Request */ ++#define SIP_INVITE 0x01 ++#define SIP_ACK 0x02 ++#define SIP_BYE 0x04 ++/* SIP Response */ ++#define SIP_100 0x10 ++#define SIP_200 0x20 ++#define SIP_200_BYE 0x40 ++/* SIP session direction */ ++#define SIP_OUTGOING 0 ++#define SIP_INCOMING 1 ++ ++enum ip_ct_conntype ++{ ++ CONN_SIP, ++ CONN_RTP, ++ CONN_RTCP, ++}; ++ ++/* This structure is per expected connection */ ++struct ip_ct_sip_expect ++{ ++ u_int16_t port; /* TCP port that was to be used */ ++ ++ enum ip_ct_conntype type; ++ int nated; ++}; ++ ++/* This structure exists only once per master */ ++struct ip_ct_sip_master { ++ int mangled; ++ u_int16_t rtpport; ++}; ++ ++extern u_int16_t find_sdp_audio_port(const char *data, size_t dlen, ++ unsigned int *numoff, unsigned int *numlen); ++extern int find_sdp_rtp_addr(const char *data, size_t dlen, ++ unsigned int *numoff, unsigned int *numlen, u_int32_t *addr); ++#endif /* _IP_CONNTRACK_SIP_H */ diff --git a/openwrt/target/linux/linux-2.4/patches/generic/117-netfilter_nat_h323.patch b/openwrt/target/linux/linux-2.4/patches/generic/117-netfilter_nat_h323.patch new file mode 100644 index 0000000000..e18627a73d --- /dev/null +++ b/openwrt/target/linux/linux-2.4/patches/generic/117-netfilter_nat_h323.patch @@ -0,0 +1,821 @@ +diff -urN linux-2.4.30/net/ipv4/netfilter/Config.in linux-2.4.30.new/net/ipv4/netfilter/Config.in +--- linux-2.4.30/net/ipv4/netfilter/Config.in 2006-02-07 15:42:18.000000000 +0100 ++++ linux-2.4.30.new/net/ipv4/netfilter/Config.in 2006-02-07 15:42:53.000000000 +0100 +@@ -14,6 +14,7 @@ + dep_tristate ' GRE protocol support' CONFIG_IP_NF_CT_PROTO_GRE $CONFIG_IP_NF_CONNTRACK + dep_tristate ' PPTP protocol support' CONFIG_IP_NF_PPTP $CONFIG_IP_NF_CT_PROTO_GRE + dep_tristate ' SIP protocol support' CONFIG_IP_NF_SIP $CONFIG_IP_NF_CONNTRACK ++ dep_tristate ' H.323 (netmeeting) support' CONFIG_IP_NF_H323 $CONFIG_IP_NF_CONNTRACK + fi + + if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then +@@ -95,6 +96,13 @@ + define_tristate CONFIG_IP_NF_NAT_SIP $CONFIG_IP_NF_NAT + fi + fi ++ if [ "$CONFIG_IP_NF_H323" = "m" ]; then ++ define_tristate CONFIG_IP_NF_NAT_H323 m ++ else ++ if [ "$CONFIG_IP_NF_H323" = "y" ]; then ++ define_tristate CONFIG_IP_NF_NAT_H323 $CONFIG_IP_NF_NAT ++ fi ++ fi + if [ "$CONFIG_IP_NF_AMANDA" = "m" ]; then + define_tristate CONFIG_IP_NF_NAT_AMANDA m + else +diff -urN linux-2.4.30/net/ipv4/netfilter/ip_conntrack_h323.c linux-2.4.30.new/net/ipv4/netfilter/ip_conntrack_h323.c +--- linux-2.4.30/net/ipv4/netfilter/ip_conntrack_h323.c 1970-01-01 01:00:00.000000000 +0100 ++++ linux-2.4.30.new/net/ipv4/netfilter/ip_conntrack_h323.c 2006-02-07 15:42:53.000000000 +0100 +@@ -0,0 +1,302 @@ ++/* ++ * H.323 'brute force' extension for H.323 connection tracking. ++ * Jozsef Kadlecsik ++ * ++ * Based on ip_masq_h323.c for 2.2 kernels from CoRiTel, Sofia project. ++ * (http://www.coritel.it/projects/sofia/nat/) ++ * Uses Sampsa Ranta's excellent idea on using expectfn to 'bind' ++ * the unregistered helpers to the conntrack entries. ++ */ ++ ++ ++#include ++#include ++#include ++#include ++#include ++ ++#include ++#include ++#include ++#include ++#include ++#include ++ ++MODULE_AUTHOR("Jozsef Kadlecsik "); ++MODULE_DESCRIPTION("H.323 'brute force' connection tracking module"); ++MODULE_LICENSE("GPL"); ++ ++DECLARE_LOCK(ip_h323_lock); ++struct module *ip_conntrack_h323 = THIS_MODULE; ++ ++#define DEBUGP(format, args...) ++ ++static int h245_help(const struct iphdr *iph, size_t len, ++ struct ip_conntrack *ct, ++ enum ip_conntrack_info ctinfo) ++{ ++ struct tcphdr *tcph = (void *)iph + iph->ihl * 4; ++ unsigned char *data = (unsigned char *) tcph + tcph->doff * 4; ++ unsigned char *data_limit; ++ u_int32_t tcplen = len - iph->ihl * 4; ++ u_int32_t datalen = tcplen - tcph->doff * 4; ++ int dir = CTINFO2DIR(ctinfo); ++ struct ip_ct_h225_master *info = &ct->help.ct_h225_info; ++ struct ip_conntrack_expect expect, *exp = &expect; ++ struct ip_ct_h225_expect *exp_info = &exp->help.exp_h225_info; ++ u_int16_t data_port; ++ u_int32_t data_ip; ++ unsigned int i; ++ ++ DEBUGP("ct_h245_help: help entered %u.%u.%u.%u:%u->%u.%u.%u.%u:%u\n", ++ NIPQUAD(iph->saddr), ntohs(tcph->source), ++ NIPQUAD(iph->daddr), ntohs(tcph->dest)); ++ ++ /* Can't track connections formed before we registered */ ++ if (!info) ++ return NF_ACCEPT; ++ ++ /* Until there's been traffic both ways, don't look in packets. */ ++ if (ctinfo != IP_CT_ESTABLISHED ++ && ctinfo != IP_CT_ESTABLISHED + IP_CT_IS_REPLY) { ++ DEBUGP("ct_h245_help: Conntrackinfo = %u\n", ctinfo); ++ return NF_ACCEPT; ++ } ++ ++ /* Not whole TCP header or too short packet? */ ++ if (tcplen < sizeof(struct tcphdr) || tcplen < tcph->doff * 4 + 5) { ++ DEBUGP("ct_h245_help: tcplen = %u\n", (unsigned)tcplen); ++ return NF_ACCEPT; ++ } ++ ++ /* Checksum invalid? Ignore. */ ++ if (tcp_v4_check(tcph, tcplen, iph->saddr, iph->daddr, ++ csum_partial((char *)tcph, tcplen, 0))) { ++ DEBUGP("ct_h245_help: bad csum: %p %u %u.%u.%u.%u %u.%u.%u.%u\n", ++ tcph, tcplen, NIPQUAD(iph->saddr), ++ NIPQUAD(iph->daddr)); ++ return NF_ACCEPT; ++ } ++ ++ data_limit = (unsigned char *) data + datalen; ++ /* bytes: 0123 45 ++ ipadrr port */ ++ for (i = 0; data < (data_limit - 5); data++, i++) { ++ memcpy(&data_ip, data, sizeof(u_int32_t)); ++ if (data_ip == iph->saddr) { ++ memcpy(&data_port, data + 4, sizeof(u_int16_t)); ++ memset(&expect, 0, sizeof(expect)); ++ /* update the H.225 info */ ++ DEBUGP("ct_h245_help: new RTCP/RTP requested %u.%u.%u.%u:->%u.%u.%u.%u:%u\n", ++ NIPQUAD(ct->tuplehash[!dir].tuple.src.ip), ++ NIPQUAD(iph->saddr), ntohs(data_port)); ++ LOCK_BH(&ip_h323_lock); ++ info->is_h225 = H225_PORT + 1; ++ exp_info->port = data_port; ++ exp_info->dir = dir; ++ exp_info->offset = i; ++ ++ exp->seq = ntohl(tcph->seq) + i; ++ ++ exp->tuple = ((struct ip_conntrack_tuple) ++ { { ct->tuplehash[!dir].tuple.src.ip, ++ { 0 } }, ++ { data_ip, ++ { data_port }, ++ IPPROTO_UDP }}); ++ exp->mask = ((struct ip_conntrack_tuple) ++ { { 0xFFFFFFFF, { 0 } }, ++ { 0xFFFFFFFF, { 0xFFFF }, 0xFFFF }}); ++ ++ exp->expectfn = NULL; ++ ++ /* Ignore failure; should only happen with NAT */ ++ ip_conntrack_expect_related(ct, exp); ++ ++ UNLOCK_BH(&ip_h323_lock); ++ } ++ } ++ ++ return NF_ACCEPT; ++ ++} ++ ++/* H.245 helper is not registered! */ ++static struct ip_conntrack_helper h245 = ++ { { NULL, NULL }, ++ "H.245", /* name */ ++ IP_CT_HELPER_F_REUSE_EXPECT, /* flags */ ++ NULL, /* module */ ++ 8, /* max_ expected */ ++ 240, /* timeout */ ++ { { 0, { 0 } }, /* tuple */ ++ { 0, { 0 }, IPPROTO_TCP } }, ++ { { 0, { 0xFFFF } }, /* mask */ ++ { 0, { 0 }, 0xFFFF } }, ++ h245_help /* helper */ ++ }; ++ ++static int h225_expect(struct ip_conntrack *ct) ++{ ++ WRITE_LOCK(&ip_conntrack_lock); ++ ct->helper = &h245; ++ DEBUGP("h225_expect: helper for %p added\n", ct); ++ WRITE_UNLOCK(&ip_conntrack_lock); ++ ++ return NF_ACCEPT; /* unused */ ++} ++ ++static int h225_help(const struct iphdr *iph, size_t len, ++ struct ip_conntrack *ct, ++ enum ip_conntrack_info ctinfo) ++{ ++ struct tcphdr *tcph = (void *)iph + iph->ihl * 4; ++ unsigned char *data = (unsigned char *) tcph + tcph->doff * 4; ++ unsigned char *data_limit; ++ u_int32_t tcplen = len - iph->ihl * 4; ++ u_int32_t datalen = tcplen - tcph->doff * 4; ++ int dir = CTINFO2DIR(ctinfo); ++ struct ip_ct_h225_master *info = &ct->help.ct_h225_info; ++ struct ip_conntrack_expect expect, *exp = &expect; ++ struct ip_ct_h225_expect *exp_info = &exp->help.exp_h225_info; ++ u_int16_t data_port; ++ u_int32_t data_ip; ++ unsigned int i; ++ ++ DEBUGP("ct_h225_help: help entered %u.%u.%u.%u:%u->%u.%u.%u.%u:%u\n", ++ NIPQUAD(iph->saddr), ntohs(tcph->source), ++ NIPQUAD(iph->daddr), ntohs(tcph->dest)); ++ ++ /* Can't track connections formed before we registered */ ++ if (!info) ++ return NF_ACCEPT; ++ ++ /* Until there's been traffic both ways, don't look in packets. */ ++ if (ctinfo != IP_CT_ESTABLISHED ++ && ctinfo != IP_CT_ESTABLISHED + IP_CT_IS_REPLY) { ++ DEBUGP("ct_h225_help: Conntrackinfo = %u\n", ctinfo); ++ return NF_ACCEPT; ++ } ++ ++ /* Not whole TCP header or too short packet? */ ++ if (tcplen < sizeof(struct tcphdr) || tcplen < tcph->doff * 4 + 5) { ++ DEBUGP("ct_h225_help: tcplen = %u\n", (unsigned)tcplen); ++ return NF_ACCEPT; ++ } ++ ++ /* Checksum invalid? Ignore. */ ++ if (tcp_v4_check(tcph, tcplen, iph->saddr, iph->daddr, ++ csum_partial((char *)tcph, tcplen, 0))) { ++ DEBUGP("ct_h225_help: bad csum: %p %u %u.%u.%u.%u %u.%u.%u.%u\n", ++ tcph, tcplen, NIPQUAD(iph->saddr), ++ NIPQUAD(iph->daddr)); ++ return NF_ACCEPT; ++ } ++ ++ data_limit = (unsigned char *) data + datalen; ++ /* bytes: 0123 45 ++ ipadrr port */ ++ for (i = 0; data < (data_limit - 5); data++, i++) { ++ memcpy(&data_ip, data, sizeof(u_int32_t)); ++ if (data_ip == iph->saddr) { ++ memcpy(&data_port, data + 4, sizeof(u_int16_t)); ++ if (data_port == tcph->source) { ++ /* Signal address */ ++ DEBUGP("ct_h225_help: sourceCallSignalAddress from %u.%u.%u.%u\n", ++ NIPQUAD(iph->saddr)); ++ /* Update the H.225 info so that NAT can mangle the address/port ++ even when we have no expected connection! */ ++#ifdef CONFIG_IP_NF_NAT_NEEDED ++ LOCK_BH(&ip_h323_lock); ++ info->dir = dir; ++ info->seq[IP_CT_DIR_ORIGINAL] = ntohl(tcph->seq) + i; ++ info->offset[IP_CT_DIR_ORIGINAL] = i; ++ UNLOCK_BH(&ip_h323_lock); ++#endif ++ } else { ++ memset(&expect, 0, sizeof(expect)); ++ ++ /* update the H.225 info */ ++ LOCK_BH(&ip_h323_lock); ++ info->is_h225 = H225_PORT; ++ exp_info->port = data_port; ++ exp_info->dir = dir; ++ exp_info->offset = i; ++ ++ exp->seq = ntohl(tcph->seq) + i; ++ ++ exp->tuple = ((struct ip_conntrack_tuple) ++ { { ct->tuplehash[!dir].tuple.src.ip, ++ { 0 } }, ++ { data_ip, ++ { data_port }, ++ IPPROTO_TCP }}); ++ exp->mask = ((struct ip_conntrack_tuple) ++ { { 0xFFFFFFFF, { 0 } }, ++ { 0xFFFFFFFF, { 0xFFFF }, 0xFFFF }}); ++ ++ exp->expectfn = h225_expect; ++ ++ /* Ignore failure */ ++ ip_conntrack_expect_related(ct, exp); ++ ++ DEBUGP("ct_h225_help: new H.245 requested %u.%u.%u.%u->%u.%u.%u.%u:%u\n", ++ NIPQUAD(ct->tuplehash[!dir].tuple.src.ip), ++ NIPQUAD(iph->saddr), ntohs(data_port)); ++ ++ UNLOCK_BH(&ip_h323_lock); ++ } ++#ifdef CONFIG_IP_NF_NAT_NEEDED ++ } else if (data_ip == iph->daddr) { ++ memcpy(&data_port, data + 4, sizeof(u_int16_t)); ++ if (data_port == tcph->dest) { ++ /* Signal address */ ++ DEBUGP("ct_h225_help: destCallSignalAddress %u.%u.%u.%u\n", ++ NIPQUAD(iph->daddr)); ++ /* Update the H.225 info so that NAT can mangle the address/port ++ even when we have no expected connection! */ ++ LOCK_BH(&ip_h323_lock); ++ info->dir = dir; ++ info->seq[IP_CT_DIR_REPLY] = ntohl(tcph->seq) + i; ++ info->offset[IP_CT_DIR_REPLY] = i; ++ UNLOCK_BH(&ip_h323_lock); ++ } ++#endif ++ } ++ } ++ ++ return NF_ACCEPT; ++ ++} ++ ++static struct ip_conntrack_helper h225 = ++ { { NULL, NULL }, ++ "H.225", /* name */ ++ IP_CT_HELPER_F_REUSE_EXPECT, /* flags */ ++ THIS_MODULE, /* module */ ++ 2, /* max_expected */ ++ 240, /* timeout */ ++ { { 0, { __constant_htons(H225_PORT) } }, /* tuple */ ++ { 0, { 0 }, IPPROTO_TCP } }, ++ { { 0, { 0xFFFF } }, /* mask */ ++ { 0, { 0 }, 0xFFFF } }, ++ h225_help /* helper */ ++ }; ++ ++static int __init init(void) ++{ ++ return ip_conntrack_helper_register(&h225); ++} ++ ++static void __exit fini(void) ++{ ++ /* Unregister H.225 helper */ ++ ip_conntrack_helper_unregister(&h225); ++} ++ ++#ifdef CONFIG_IP_NF_NAT_NEEDED ++EXPORT_SYMBOL(ip_h323_lock); ++#endif ++ ++module_init(init); ++module_exit(fini); +diff -urN linux-2.4.30/net/ipv4/netfilter/ip_nat_h323.c linux-2.4.30.new/net/ipv4/netfilter/ip_nat_h323.c +--- linux-2.4.30/net/ipv4/netfilter/ip_nat_h323.c 1970-01-01 01:00:00.000000000 +0100 ++++ linux-2.4.30.new/net/ipv4/netfilter/ip_nat_h323.c 2006-02-07 15:42:53.000000000 +0100 +@@ -0,0 +1,403 @@ ++/* ++ * H.323 'brute force' extension for NAT alteration. ++ * Jozsef Kadlecsik ++ * ++ * Based on ip_masq_h323.c for 2.2 kernels from CoRiTel, Sofia project. ++ * (http://www.coritel.it/projects/sofia/nat.html) ++ * Uses Sampsa Ranta's excellent idea on using expectfn to 'bind' ++ * the unregistered helpers to the conntrack entries. ++ */ ++ ++ ++#include ++#include ++#include ++#include ++#include ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++MODULE_AUTHOR("Jozsef Kadlecsik "); ++MODULE_DESCRIPTION("H.323 'brute force' connection tracking module"); ++MODULE_LICENSE("GPL"); ++ ++DECLARE_LOCK_EXTERN(ip_h323_lock); ++struct module *ip_nat_h323 = THIS_MODULE; ++ ++#define DEBUGP(format, args...) ++ ++ ++static unsigned int ++h225_nat_expected(struct sk_buff **pskb, ++ unsigned int hooknum, ++ struct ip_conntrack *ct, ++ struct ip_nat_info *info); ++ ++static unsigned int h225_nat_help(struct ip_conntrack *ct, ++ struct ip_conntrack_expect *exp, ++ struct ip_nat_info *info, ++ enum ip_conntrack_info ctinfo, ++ unsigned int hooknum, ++ struct sk_buff **pskb); ++ ++static struct ip_nat_helper h245 = ++ { { NULL, NULL }, ++ "H.245", /* name */ ++ 0, /* flags */ ++ NULL, /* module */ ++ { { 0, { 0 } }, /* tuple */ ++ { 0, { 0 }, IPPROTO_TCP } }, ++ { { 0, { 0xFFFF } }, /* mask */ ++ { 0, { 0 }, 0xFFFF } }, ++ h225_nat_help, /* helper */ ++ h225_nat_expected /* expectfn */ ++ }; ++ ++static unsigned int ++h225_nat_expected(struct sk_buff **pskb, ++ unsigned int hooknum, ++ struct ip_conntrack *ct, ++ struct ip_nat_info *info) ++{ ++ struct ip_nat_multi_range mr; ++ u_int32_t newdstip, newsrcip, newip; ++ u_int16_t port; ++ struct ip_ct_h225_expect *exp_info; ++ struct ip_ct_h225_master *master_info; ++ struct ip_conntrack *master = master_ct(ct); ++ unsigned int is_h225, ret; ++ ++ IP_NF_ASSERT(info); ++ IP_NF_ASSERT(master); ++ ++ IP_NF_ASSERT(!(info->initialized & (1<master->expectant->help.ct_h225_info; ++ exp_info = &ct->master->help.exp_h225_info; ++ ++ LOCK_BH(&ip_h323_lock); ++ ++ DEBUGP("master: "); ++ DUMP_TUPLE(&master->tuplehash[IP_CT_DIR_ORIGINAL].tuple); ++ DUMP_TUPLE(&master->tuplehash[IP_CT_DIR_REPLY].tuple); ++ DEBUGP("conntrack: "); ++ DUMP_TUPLE(&ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple); ++ if (exp_info->dir == IP_CT_DIR_ORIGINAL) { ++ /* Make connection go to the client. */ ++ newdstip = master->tuplehash[IP_CT_DIR_ORIGINAL].tuple.src.ip; ++ newsrcip = master->tuplehash[IP_CT_DIR_ORIGINAL].tuple.dst.ip; ++ DEBUGP("h225_nat_expected: %u.%u.%u.%u->%u.%u.%u.%u (to client)\n", ++ NIPQUAD(newsrcip), NIPQUAD(newdstip)); ++ } else { ++ /* Make the connection go to the server */ ++ newdstip = master->tuplehash[IP_CT_DIR_REPLY].tuple.src.ip; ++ newsrcip = master->tuplehash[IP_CT_DIR_REPLY].tuple.dst.ip; ++ DEBUGP("h225_nat_expected: %u.%u.%u.%u->%u.%u.%u.%u (to server)\n", ++ NIPQUAD(newsrcip), NIPQUAD(newdstip)); ++ } ++ port = exp_info->port; ++ is_h225 = master_info->is_h225 == H225_PORT; ++ UNLOCK_BH(&ip_h323_lock); ++ ++ if (HOOK2MANIP(hooknum) == IP_NAT_MANIP_SRC) ++ newip = newsrcip; ++ else ++ newip = newdstip; ++ ++ DEBUGP("h225_nat_expected: IP to %u.%u.%u.%u\n", NIPQUAD(newip)); ++ ++ mr.rangesize = 1; ++ /* We don't want to manip the per-protocol, just the IPs... */ ++ mr.range[0].flags = IP_NAT_RANGE_MAP_IPS; ++ mr.range[0].min_ip = mr.range[0].max_ip = newip; ++ ++ /* ... unless we're doing a MANIP_DST, in which case, make ++ sure we map to the correct port */ ++ if (HOOK2MANIP(hooknum) == IP_NAT_MANIP_DST) { ++ mr.range[0].flags |= IP_NAT_RANGE_PROTO_SPECIFIED; ++ mr.range[0].min = mr.range[0].max ++ = ((union ip_conntrack_manip_proto) ++ { port }); ++ } ++ ++ ret = ip_nat_setup_info(ct, &mr, hooknum); ++ ++ if (is_h225) { ++ DEBUGP("h225_nat_expected: H.225, setting NAT helper for %p\n", ct); ++ /* NAT expectfn called with ip_nat_lock write-locked */ ++ info->helper = &h245; ++ } ++ return ret; ++} ++ ++static int h323_signal_address_fixup(struct ip_conntrack *ct, ++ struct sk_buff **pskb, ++ enum ip_conntrack_info ctinfo) ++{ ++ struct iphdr *iph = (*pskb)->nh.iph; ++ struct tcphdr *tcph = (void *)iph + iph->ihl*4; ++ unsigned char *data; ++ u_int32_t tcplen = (*pskb)->len - iph->ihl*4; ++ u_int32_t datalen = tcplen - tcph->doff*4; ++ struct ip_ct_h225_master *info = &ct->help.ct_h225_info; ++ u_int32_t newip; ++ u_int16_t port; ++ u_int8_t buffer[6]; ++ int i; ++ ++ MUST_BE_LOCKED(&ip_h323_lock); ++ ++ DEBUGP("h323_signal_address_fixup: %s %s\n", ++ between(info->seq[IP_CT_DIR_ORIGINAL], ntohl(tcph->seq), ntohl(tcph->seq) + datalen) ++ ? "yes" : "no", ++ between(info->seq[IP_CT_DIR_REPLY], ntohl(tcph->seq), ntohl(tcph->seq) + datalen) ++ ? "yes" : "no"); ++ if (!(between(info->seq[IP_CT_DIR_ORIGINAL], ntohl(tcph->seq), ntohl(tcph->seq) + datalen) ++ || between(info->seq[IP_CT_DIR_REPLY], ntohl(tcph->seq), ntohl(tcph->seq) + datalen))) ++ return 1; ++ ++ DEBUGP("h323_signal_address_fixup: offsets %u + 6 and %u + 6 in %u\n", ++ info->offset[IP_CT_DIR_ORIGINAL], ++ info->offset[IP_CT_DIR_REPLY], ++ tcplen); ++ DUMP_TUPLE(&ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple); ++ DUMP_TUPLE(&ct->tuplehash[IP_CT_DIR_REPLY].tuple); ++ ++ for (i = 0; i < IP_CT_DIR_MAX; i++) { ++ DEBUGP("h323_signal_address_fixup: %s %s\n", ++ info->dir == IP_CT_DIR_ORIGINAL ? "original" : "reply", ++ i == IP_CT_DIR_ORIGINAL ? "caller" : "callee"); ++ if (!between(info->seq[i], ntohl(tcph->seq), ++ ntohl(tcph->seq) + datalen)) ++ continue; ++ if (!between(info->seq[i] + 6, ntohl(tcph->seq), ++ ntohl(tcph->seq) + datalen)) { ++ /* Partial retransmisison. It's a cracker being funky. */ ++ if (net_ratelimit()) { ++ printk("H.323_NAT: partial packet %u/6 in %u/%u\n", ++ info->seq[i], ++ ntohl(tcph->seq), ++ ntohl(tcph->seq) + datalen); ++ } ++ return 0; ++ } ++ ++ /* Change address inside packet to match way we're mapping ++ this connection. */ ++ if (i == IP_CT_DIR_ORIGINAL) { ++ newip = ct->tuplehash[!info->dir].tuple.dst.ip; ++ port = ct->tuplehash[!info->dir].tuple.dst.u.tcp.port; ++ } else { ++ newip = ct->tuplehash[!info->dir].tuple.src.ip; ++ port = ct->tuplehash[!info->dir].tuple.src.u.tcp.port; ++ } ++ ++ data = (char *) tcph + tcph->doff * 4 + info->offset[i]; ++ ++ DEBUGP("h323_signal_address_fixup: orig %s IP:port %u.%u.%u.%u:%u\n", ++ i == IP_CT_DIR_ORIGINAL ? "source" : "dest ", ++ data[0], data[1], data[2], data[3], ++ (data[4] << 8 | data[5])); ++ ++ /* Modify the packet */ ++ memcpy(buffer, &newip, 4); ++ memcpy(buffer + 4, &port, 2); ++ if (!ip_nat_mangle_tcp_packet(pskb, ct, ctinfo, info->offset[i], ++ 6, buffer, 6)) ++ return 0; ++ ++ DEBUGP("h323_signal_address_fixup: new %s IP:port %u.%u.%u.%u:%u\n", ++ i == IP_CT_DIR_ORIGINAL ? "source" : "dest ", ++ data[0], data[1], data[2], data[3], ++ (data[4] << 8 | data[5])); ++ } ++ ++ return 1; ++} ++ ++static int h323_data_fixup(struct ip_ct_h225_expect *info, ++ struct ip_conntrack *ct, ++ struct sk_buff **pskb, ++ enum ip_conntrack_info ctinfo, ++ struct ip_conntrack_expect *expect) ++{ ++ u_int32_t newip; ++ u_int16_t port; ++ u_int8_t buffer[6]; ++ struct ip_conntrack_tuple newtuple; ++ struct iphdr *iph = (*pskb)->nh.iph; ++ struct tcphdr *tcph = (void *)iph + iph->ihl*4; ++ unsigned char *data; ++ u_int32_t tcplen = (*pskb)->len - iph->ihl*4; ++ struct ip_ct_h225_master *master_info = &ct->help.ct_h225_info; ++ int is_h225; ++ ++ MUST_BE_LOCKED(&ip_h323_lock); ++ DEBUGP("h323_data_fixup: offset %u + 6 in %u\n", info->offset, tcplen); ++ DUMP_TUPLE(&ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple); ++ DUMP_TUPLE(&ct->tuplehash[IP_CT_DIR_REPLY].tuple); ++ ++ if (!between(expect->seq + 6, ntohl(tcph->seq), ++ ntohl(tcph->seq) + tcplen - tcph->doff * 4)) { ++ /* Partial retransmisison. It's a cracker being funky. */ ++ if (net_ratelimit()) { ++ printk("H.323_NAT: partial packet %u/6 in %u/%u\n", ++ expect->seq, ++ ntohl(tcph->seq), ++ ntohl(tcph->seq) + tcplen - tcph->doff * 4); ++ } ++ return 0; ++ } ++ ++ /* Change address inside packet to match way we're mapping ++ this connection. */ ++ if (info->dir == IP_CT_DIR_REPLY) { ++ /* Must be where client thinks server is */ ++ newip = ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple.dst.ip; ++ /* Expect something from client->server */ ++ newtuple.src.ip = ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple.src.ip; ++ newtuple.dst.ip = ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple.dst.ip; ++ } else { ++ /* Must be where server thinks client is */ ++ newip = ct->tuplehash[IP_CT_DIR_REPLY].tuple.dst.ip; ++ /* Expect something from server->client */ ++ newtuple.src.ip = ct->tuplehash[IP_CT_DIR_REPLY].tuple.src.ip; ++ newtuple.dst.ip = ct->tuplehash[IP_CT_DIR_REPLY].tuple.dst.ip; ++ } ++ ++ is_h225 = (master_info->is_h225 == H225_PORT); ++ ++ if (is_h225) { ++ newtuple.dst.protonum = IPPROTO_TCP; ++ newtuple.src.u.tcp.port = expect->tuple.src.u.tcp.port; ++ } else { ++ newtuple.dst.protonum = IPPROTO_UDP; ++ newtuple.src.u.udp.port = expect->tuple.src.u.udp.port; ++ } ++ ++ /* Try to get same port: if not, try to change it. */ ++ for (port = ntohs(info->port); port != 0; port++) { ++ if (is_h225) ++ newtuple.dst.u.tcp.port = htons(port); ++ else ++ newtuple.dst.u.udp.port = htons(port); ++ ++ if (ip_conntrack_change_expect(expect, &newtuple) == 0) ++ break; ++ } ++ if (port == 0) { ++ DEBUGP("h323_data_fixup: no free port found!\n"); ++ return 0; ++ } ++ ++ port = htons(port); ++ ++ data = (char *) tcph + tcph->doff * 4 + info->offset; ++ ++ DEBUGP("h323_data_fixup: orig IP:port %u.%u.%u.%u:%u\n", ++ data[0], data[1], data[2], data[3], ++ (data[4] << 8 | data[5])); ++ ++ /* Modify the packet */ ++ memcpy(buffer, &newip, 4); ++ memcpy(buffer + 4, &port, 2); ++ if (!ip_nat_mangle_tcp_packet(pskb, ct, ctinfo, info->offset, ++ 6, buffer, 6)) ++ return 0; ++ ++ DEBUGP("h323_data_fixup: new IP:port %u.%u.%u.%u:%u\n", ++ data[0], data[1], data[2], data[3], ++ (data[4] << 8 | data[5])); ++ ++ return 1; ++} ++ ++static unsigned int h225_nat_help(struct ip_conntrack *ct, ++ struct ip_conntrack_expect *exp, ++ struct ip_nat_info *info, ++ enum ip_conntrack_info ctinfo, ++ unsigned int hooknum, ++ struct sk_buff **pskb) ++{ ++ int dir; ++ struct ip_ct_h225_expect *exp_info; ++ ++ /* Only mangle things once: original direction in POST_ROUTING ++ and reply direction on PRE_ROUTING. */ ++ dir = CTINFO2DIR(ctinfo); ++ DEBUGP("nat_h323: dir %s at hook %s\n", ++ dir == IP_CT_DIR_ORIGINAL ? "ORIG" : "REPLY", ++ hooknum == NF_IP_POST_ROUTING ? "POSTROUTING" ++ : hooknum == NF_IP_PRE_ROUTING ? "PREROUTING" ++ : hooknum == NF_IP_LOCAL_OUT ? "OUTPUT" : "???"); ++ if (!((hooknum == NF_IP_POST_ROUTING && dir == IP_CT_DIR_ORIGINAL) ++ || (hooknum == NF_IP_PRE_ROUTING && dir == IP_CT_DIR_REPLY))) { ++ DEBUGP("nat_h323: Not touching dir %s at hook %s\n", ++ dir == IP_CT_DIR_ORIGINAL ? "ORIG" : "REPLY", ++ hooknum == NF_IP_POST_ROUTING ? "POSTROUTING" ++ : hooknum == NF_IP_PRE_ROUTING ? "PREROUTING" ++ : hooknum == NF_IP_LOCAL_OUT ? "OUTPUT" : "???"); ++ return NF_ACCEPT; ++ } ++ ++ if (!exp) { ++ LOCK_BH(&ip_h323_lock); ++ if (!h323_signal_address_fixup(ct, pskb, ctinfo)) { ++ UNLOCK_BH(&ip_h323_lock); ++ return NF_DROP; ++ } ++ UNLOCK_BH(&ip_h323_lock); ++ return NF_ACCEPT; ++ } ++ ++ exp_info = &exp->help.exp_h225_info; ++ ++ LOCK_BH(&ip_h323_lock); ++ if (!h323_data_fixup(exp_info, ct, pskb, ctinfo, exp)) { ++ UNLOCK_BH(&ip_h323_lock); ++ return NF_DROP; ++ } ++ UNLOCK_BH(&ip_h323_lock); ++ ++ return NF_ACCEPT; ++} ++ ++static struct ip_nat_helper h225 = ++ { { NULL, NULL }, ++ "H.225", /* name */ ++ IP_NAT_HELPER_F_ALWAYS, /* flags */ ++ THIS_MODULE, /* module */ ++ { { 0, { __constant_htons(H225_PORT) } }, /* tuple */ ++ { 0, { 0 }, IPPROTO_TCP } }, ++ { { 0, { 0xFFFF } }, /* mask */ ++ { 0, { 0 }, 0xFFFF } }, ++ h225_nat_help, /* helper */ ++ h225_nat_expected /* expectfn */ ++ }; ++ ++static int __init init(void) ++{ ++ int ret; ++ ++ ret = ip_nat_helper_register(&h225); ++ ++ if (ret != 0) ++ printk("ip_nat_h323: cannot initialize the module!\n"); ++ ++ return ret; ++} ++ ++static void __exit fini(void) ++{ ++ ip_nat_helper_unregister(&h225); ++} ++ ++module_init(init); ++module_exit(fini); +diff -urN linux-2.4.30/net/ipv4/netfilter/Makefile linux-2.4.30.new/net/ipv4/netfilter/Makefile +--- linux-2.4.30/net/ipv4/netfilter/Makefile 2006-02-07 15:42:18.000000000 +0100 ++++ linux-2.4.30.new/net/ipv4/netfilter/Makefile 2006-02-07 15:42:53.000000000 +0100 +@@ -57,6 +57,10 @@ + ifdef CONFIG_IP_NF_NAT_SIP + export-objs += ip_conntrack_sip.o + endif ++obj-$(CONFIG_IP_NF_H323) += ip_conntrack_h323.o ++ifdef CONFIG_IP_NF_NAT_H323 ++ export-objs += ip_conntrack_h323.o ++endif + + + # NAT helpers +@@ -67,6 +71,7 @@ + obj-$(CONFIG_IP_NF_NAT_PROTO_GRE) += ip_nat_proto_gre.o + obj-$(CONFIG_IP_NF_NAT_PPTP) += ip_nat_pptp.o + obj-$(CONFIG_IP_NF_NAT_SIP) += ip_nat_sip.o ++obj-$(CONFIG_IP_NF_NAT_H323) += ip_nat_h323.o + + # generic IP tables + obj-$(CONFIG_IP_NF_IPTABLES) += ip_tables.o +diff -urN linux-2.4.30/include/linux/netfilter_ipv4/ip_conntrack.h linux-2.4.30.new/include/linux/netfilter_ipv4/ip_conntrack.h +--- linux-2.4.30/include/linux/netfilter_ipv4/ip_conntrack.h 2006-02-07 15:42:18.000000000 +0100 ++++ linux-2.4.30.new/include/linux/netfilter_ipv4/ip_conntrack.h 2006-02-07 15:42:53.000000000 +0100 +@@ -72,6 +72,7 @@ + #include + #include + #include ++#include + + /* per expectation: application helper private data */ + union ip_conntrack_expect_help { +@@ -81,6 +82,7 @@ + struct ip_ct_irc_expect exp_irc_info; + struct ip_ct_pptp_expect exp_pptp_info; + struct ip_ct_sip_expect exp_sip_info; ++ struct ip_ct_h225_expect exp_h225_info; + + #ifdef CONFIG_IP_NF_NAT_NEEDED + union { +@@ -96,6 +98,7 @@ + struct ip_ct_irc_master ct_irc_info; + struct ip_ct_pptp_master ct_pptp_info; + struct ip_ct_sip_master ct_sip_info; ++ struct ip_ct_h225_master ct_h225_info; + }; + + #ifdef CONFIG_IP_NF_NAT_NEEDED +diff -urN linux-2.4.30/include/linux/netfilter_ipv4/ip_conntrack_h323.h linux-2.4.30.new/include/linux/netfilter_ipv4/ip_conntrack_h323.h +--- linux-2.4.30/include/linux/netfilter_ipv4/ip_conntrack_h323.h 1970-01-01 01:00:00.000000000 +0100 ++++ linux-2.4.30.new/include/linux/netfilter_ipv4/ip_conntrack_h323.h 2006-02-07 15:42:53.000000000 +0100 +@@ -0,0 +1,30 @@ ++#ifndef _IP_CONNTRACK_H323_H ++#define _IP_CONNTRACK_H323_H ++/* H.323 connection tracking. */ ++ ++#ifdef __KERNEL__ ++/* Protects H.323 related data */ ++DECLARE_LOCK_EXTERN(ip_h323_lock); ++#endif ++ ++/* Default H.225 port */ ++#define H225_PORT 1720 ++ ++/* This structure is per expected connection */ ++struct ip_ct_h225_expect { ++ u_int16_t port; /* Port of the H.225 helper/RTCP/RTP channel */ ++ enum ip_conntrack_dir dir; /* Direction of the original connection */ ++ unsigned int offset; /* offset of the address in the payload */ ++}; ++ ++/* This structure exists only once per master */ ++struct ip_ct_h225_master { ++ int is_h225; /* H.225 or H.245 connection */ ++#ifdef CONFIG_IP_NF_NAT_NEEDED ++ enum ip_conntrack_dir dir; /* Direction of the original connection */ ++ u_int32_t seq[IP_CT_DIR_MAX]; /* Exceptional packet mangling for signal addressess... */ ++ unsigned int offset[IP_CT_DIR_MAX]; /* ...and the offset of the addresses in the payload */ ++#endif ++}; ++ ++#endif /* _IP_CONNTRACK_H323_H */ diff --git a/openwrt/target/linux/linux-2.4/patches/generic/118-netfilter_nat_rtsp.patch b/openwrt/target/linux/linux-2.4/patches/generic/118-netfilter_nat_rtsp.patch new file mode 100644 index 0000000000..7b3c9eaf61 --- /dev/null +++ b/openwrt/target/linux/linux-2.4/patches/generic/118-netfilter_nat_rtsp.patch @@ -0,0 +1,1810 @@ +diff -urN linux-2.4.30/net/ipv4/netfilter/Config.in linux-2.4.30.new/net/ipv4/netfilter/Config.in +--- linux-2.4.30/net/ipv4/netfilter/Config.in 2006-02-07 15:44:46.000000000 +0100 ++++ linux-2.4.30.new/net/ipv4/netfilter/Config.in 2006-02-07 15:46:07.000000000 +0100 +@@ -15,6 +15,7 @@ + dep_tristate ' PPTP protocol support' CONFIG_IP_NF_PPTP $CONFIG_IP_NF_CT_PROTO_GRE + dep_tristate ' SIP protocol support' CONFIG_IP_NF_SIP $CONFIG_IP_NF_CONNTRACK + dep_tristate ' H.323 (netmeeting) support' CONFIG_IP_NF_H323 $CONFIG_IP_NF_CONNTRACK ++ dep_tristate ' RTSP protocol support' CONFIG_IP_NF_RTSP $CONFIG_IP_NF_CONNTRACK + fi + + if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then +@@ -103,6 +103,13 @@ + define_tristate CONFIG_IP_NF_NAT_H323 $CONFIG_IP_NF_NAT + fi + fi ++ if [ "$CONFIG_IP_NF_RTSP" = "m" ]; then ++ define_tristate CONFIG_IP_NF_NAT_RTSP m ++ else ++ if [ "$CONFIG_IP_NF_RTSP" = "y" ]; then ++ define_tristate CONFIG_IP_NF_NAT_RTSP $CONFIG_IP_NF_NAT ++ fi ++ fi + if [ "$CONFIG_IP_NF_AMANDA" = "m" ]; then + define_tristate CONFIG_IP_NF_NAT_AMANDA m + else +diff -urN linux-2.4.30/net/ipv4/netfilter/ip_conntrack_rtsp.c linux-2.4.30.new/net/ipv4/netfilter/ip_conntrack_rtsp.c +--- linux-2.4.30/net/ipv4/netfilter/ip_conntrack_rtsp.c 1970-01-01 01:00:00.000000000 +0100 ++++ linux-2.4.30.new/net/ipv4/netfilter/ip_conntrack_rtsp.c 2006-02-07 15:46:07.000000000 +0100 +@@ -0,0 +1,507 @@ ++/* ++ * RTSP extension for IP connection tracking ++ * (C) 2003 by Tom Marshall ++ * based on ip_conntrack_irc.c ++ * ++ * This program is free software; you can redistribute it and/or ++ * modify it under the terms of the GNU General Public License ++ * as published by the Free Software Foundation; either version ++ * 2 of the License, or (at your option) any later version. ++ * ++ * Module load syntax: ++ * insmod ip_conntrack_rtsp.o ports=port1,port2,...port ++ * max_outstanding=n setup_timeout=secs ++ * ++ * If no ports are specified, the default will be port 554. ++ * ++ * With max_outstanding you can define the maximum number of not yet ++ * answered SETUP requests per RTSP session (default 8). ++ * With setup_timeout you can specify how long the system waits for ++ * an expected data channel (default 300 seconds). ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include ++#include ++#include ++ ++#include ++#define NF_NEED_STRNCASECMP ++#define NF_NEED_STRTOU16 ++#define NF_NEED_STRTOU32 ++#define NF_NEED_NEXTLINE ++#include ++#define NF_NEED_MIME_NEXTLINE ++#include ++ ++#define MAX_SIMUL_SETUP 8 /* XXX: use max_outstanding */ ++ ++#define INFOP(fmt, args...) printk(KERN_INFO "%s: %s: " fmt, __FILE__, __FUNCTION__ , ## args) ++#ifdef IP_NF_RTSP_DEBUG ++#define DEBUGP(fmt, args...) printk(KERN_DEBUG "%s: %s: " fmt, __FILE__, __FUNCTION__ , ## args) ++#else ++#define DEBUGP(fmt, args...) ++#endif ++ ++#define MAX_PORTS 8 ++static int ports[MAX_PORTS]; ++static int num_ports = 0; ++static int max_outstanding = 8; ++static unsigned int setup_timeout = 300; ++ ++MODULE_AUTHOR("Tom Marshall "); ++MODULE_DESCRIPTION("RTSP connection tracking module"); ++MODULE_LICENSE("GPL"); ++#ifdef MODULE_PARM ++MODULE_PARM(ports, "1-" __MODULE_STRING(MAX_PORTS) "i"); ++MODULE_PARM_DESC(ports, "port numbers of RTSP servers"); ++MODULE_PARM(max_outstanding, "i"); ++MODULE_PARM_DESC(max_outstanding, "max number of outstanding SETUP requests per RTSP session"); ++MODULE_PARM(setup_timeout, "i"); ++MODULE_PARM_DESC(setup_timeout, "timeout on for unestablished data channels"); ++#endif ++ ++DECLARE_LOCK(ip_rtsp_lock); ++struct module* ip_conntrack_rtsp = THIS_MODULE; ++ ++/* ++ * Max mappings we will allow for one RTSP connection (for RTP, the number ++ * of allocated ports is twice this value). Note that SMIL burns a lot of ++ * ports so keep this reasonably high. If this is too low, you will see a ++ * lot of "no free client map entries" messages. ++ */ ++#define MAX_PORT_MAPS 16 ++ ++/*** default port list was here in the masq code: 554, 3030, 4040 ***/ ++ ++#define SKIP_WSPACE(ptr,len,off) while(off < len && isspace(*(ptr+off))) { off++; } ++ ++/* ++ * Parse an RTSP packet. ++ * ++ * Returns zero if parsing failed. ++ * ++ * Parameters: ++ * IN ptcp tcp data pointer ++ * IN tcplen tcp data len ++ * IN/OUT ptcpoff points to current tcp offset ++ * OUT phdrsoff set to offset of rtsp headers ++ * OUT phdrslen set to length of rtsp headers ++ * OUT pcseqoff set to offset of CSeq header ++ * OUT pcseqlen set to length of CSeq header ++ */ ++static int ++rtsp_parse_message(char* ptcp, uint tcplen, uint* ptcpoff, ++ uint* phdrsoff, uint* phdrslen, ++ uint* pcseqoff, uint* pcseqlen) ++{ ++ uint entitylen = 0; ++ uint lineoff; ++ uint linelen; ++ ++ if (!nf_nextline(ptcp, tcplen, ptcpoff, &lineoff, &linelen)) ++ { ++ return 0; ++ } ++ ++ *phdrsoff = *ptcpoff; ++ while (nf_mime_nextline(ptcp, tcplen, ptcpoff, &lineoff, &linelen)) ++ { ++ if (linelen == 0) ++ { ++ if (entitylen > 0) ++ { ++ *ptcpoff += min(entitylen, tcplen - *ptcpoff); ++ } ++ break; ++ } ++ if (lineoff+linelen > tcplen) ++ { ++ INFOP("!! overrun !!\n"); ++ break; ++ } ++ ++ if (nf_strncasecmp(ptcp+lineoff, "CSeq:", 5) == 0) ++ { ++ *pcseqoff = lineoff; ++ *pcseqlen = linelen; ++ } ++ if (nf_strncasecmp(ptcp+lineoff, "Content-Length:", 15) == 0) ++ { ++ uint off = lineoff+15; ++ SKIP_WSPACE(ptcp+lineoff, linelen, off); ++ nf_strtou32(ptcp+off, &entitylen); ++ } ++ } ++ *phdrslen = (*ptcpoff) - (*phdrsoff); ++ ++ return 1; ++} ++ ++/* ++ * Find lo/hi client ports (if any) in transport header ++ * In: ++ * ptcp, tcplen = packet ++ * tranoff, tranlen = buffer to search ++ * ++ * Out: ++ * pport_lo, pport_hi = lo/hi ports (host endian) ++ * ++ * Returns nonzero if any client ports found ++ * ++ * Note: it is valid (and expected) for the client to request multiple ++ * transports, so we need to parse the entire line. ++ */ ++static int ++rtsp_parse_transport(char* ptran, uint tranlen, ++ struct ip_ct_rtsp_expect* prtspexp) ++{ ++ int rc = 0; ++ uint off = 0; ++ ++ if (tranlen < 10 || !iseol(ptran[tranlen-1]) || ++ nf_strncasecmp(ptran, "Transport:", 10) != 0) ++ { ++ INFOP("sanity check failed\n"); ++ return 0; ++ } ++ DEBUGP("tran='%.*s'\n", (int)tranlen, ptran); ++ off += 10; ++ SKIP_WSPACE(ptran, tranlen, off); ++ ++ /* Transport: tran;field;field=val,tran;field;field=val,... */ ++ while (off < tranlen) ++ { ++ const char* pparamend; ++ uint nextparamoff; ++ ++ pparamend = memchr(ptran+off, ',', tranlen-off); ++ pparamend = (pparamend == NULL) ? ptran+tranlen : pparamend+1; ++ nextparamoff = pparamend-ptran; ++ ++ while (off < nextparamoff) ++ { ++ const char* pfieldend; ++ uint nextfieldoff; ++ ++ pfieldend = memchr(ptran+off, ';', nextparamoff-off); ++ nextfieldoff = (pfieldend == NULL) ? nextparamoff : pfieldend-ptran+1; ++ ++ if (strncmp(ptran+off, "client_port=", 12) == 0) ++ { ++ u_int16_t port; ++ uint numlen; ++ ++ off += 12; ++ numlen = nf_strtou16(ptran+off, &port); ++ off += numlen; ++ if (prtspexp->loport != 0 && prtspexp->loport != port) ++ { ++ DEBUGP("multiple ports found, port %hu ignored\n", port); ++ } ++ else ++ { ++ prtspexp->loport = prtspexp->hiport = port; ++ if (ptran[off] == '-') ++ { ++ off++; ++ numlen = nf_strtou16(ptran+off, &port); ++ off += numlen; ++ prtspexp->pbtype = pb_range; ++ prtspexp->hiport = port; ++ ++ // If we have a range, assume rtp: ++ // loport must be even, hiport must be loport+1 ++ if ((prtspexp->loport & 0x0001) != 0 || ++ prtspexp->hiport != prtspexp->loport+1) ++ { ++ DEBUGP("incorrect range: %hu-%hu, correcting\n", ++ prtspexp->loport, prtspexp->hiport); ++ prtspexp->loport &= 0xfffe; ++ prtspexp->hiport = prtspexp->loport+1; ++ } ++ } ++ else if (ptran[off] == '/') ++ { ++ off++; ++ numlen = nf_strtou16(ptran+off, &port); ++ off += numlen; ++ prtspexp->pbtype = pb_discon; ++ prtspexp->hiport = port; ++ } ++ rc = 1; ++ } ++ } ++ ++ /* ++ * Note we don't look for the destination parameter here. ++ * If we are using NAT, the NAT module will handle it. If not, ++ * and the client is sending packets elsewhere, the expectation ++ * will quietly time out. ++ */ ++ ++ off = nextfieldoff; ++ } ++ ++ off = nextparamoff; ++ } ++ ++ return rc; ++} ++ ++/*** conntrack functions ***/ ++ ++/* outbound packet: client->server */ ++static int ++help_out(const struct iphdr* iph, size_t pktlen, ++ struct ip_conntrack* ct, enum ip_conntrack_info ctinfo) ++{ ++ int dir = CTINFO2DIR(ctinfo); /* = IP_CT_DIR_ORIGINAL */ ++ struct tcphdr* tcph = (void*)iph + iph->ihl * 4; ++ uint tcplen = pktlen - iph->ihl * 4; ++ char* pdata = (char*)tcph + tcph->doff * 4; ++ uint datalen = tcplen - tcph->doff * 4; ++ uint dataoff = 0; ++ ++ struct ip_conntrack_expect exp; ++ ++ while (dataoff < datalen) ++ { ++ uint cmdoff = dataoff; ++ uint hdrsoff = 0; ++ uint hdrslen = 0; ++ uint cseqoff = 0; ++ uint cseqlen = 0; ++ uint lineoff = 0; ++ uint linelen = 0; ++ uint off; ++ int rc; ++ ++ if (!rtsp_parse_message(pdata, datalen, &dataoff, ++ &hdrsoff, &hdrslen, ++ &cseqoff, &cseqlen)) ++ { ++ break; /* not a valid message */ ++ } ++ ++ if (strncmp(pdata+cmdoff, "SETUP ", 6) != 0) ++ { ++ continue; /* not a SETUP message */ ++ } ++ DEBUGP("found a setup message\n"); ++ ++ memset(&exp, 0, sizeof(exp)); ++ ++ off = 0; ++ while (nf_mime_nextline(pdata+hdrsoff, hdrslen, &off, ++ &lineoff, &linelen)) ++ { ++ if (linelen == 0) ++ { ++ break; ++ } ++ if (off > hdrsoff+hdrslen) ++ { ++ INFOP("!! overrun !!"); ++ break; ++ } ++ ++ if (nf_strncasecmp(pdata+hdrsoff+lineoff, "Transport:", 10) == 0) ++ { ++ rtsp_parse_transport(pdata+hdrsoff+lineoff, linelen, ++ &exp.help.exp_rtsp_info); ++ } ++ } ++ ++ if (exp.help.exp_rtsp_info.loport == 0) ++ { ++ DEBUGP("no udp transports found\n"); ++ continue; /* no udp transports found */ ++ } ++ ++ DEBUGP("udp transport found, ports=(%d,%hu,%hu)\n", ++ (int)exp.help.exp_rtsp_info.pbtype, ++ exp.help.exp_rtsp_info.loport, ++ exp.help.exp_rtsp_info.hiport); ++ ++ LOCK_BH(&ip_rtsp_lock); ++ exp.seq = ntohl(tcph->seq) + hdrsoff; /* mark all the headers */ ++ exp.help.exp_rtsp_info.len = hdrslen; ++ ++ exp.tuple.src.ip = ct->tuplehash[!dir].tuple.src.ip; ++ exp.mask.src.ip = 0xffffffff; ++ exp.tuple.dst.ip = ct->tuplehash[dir].tuple.src.ip; ++ exp.mask.dst.ip = 0xffffffff; ++ exp.tuple.dst.u.udp.port = exp.help.exp_rtsp_info.loport; ++ exp.mask.dst.u.udp.port = (exp.help.exp_rtsp_info.pbtype == pb_range) ? 0xfffe : 0xffff; ++ exp.tuple.dst.protonum = IPPROTO_UDP; ++ exp.mask.dst.protonum = 0xffff; ++ ++ DEBUGP("expect_related %u.%u.%u.%u:%u-%u.%u.%u.%u:%u\n", ++ NIPQUAD(exp.tuple.src.ip), ++ ntohs(exp.tuple.src.u.tcp.port), ++ NIPQUAD(exp.tuple.dst.ip), ++ ntohs(exp.tuple.dst.u.tcp.port)); ++ ++ /* pass the request off to the nat helper */ ++ rc = ip_conntrack_expect_related(ct, &exp); ++ UNLOCK_BH(&ip_rtsp_lock); ++ if (rc == 0) ++ { ++ DEBUGP("ip_conntrack_expect_related succeeded\n"); ++ } ++ else ++ { ++ INFOP("ip_conntrack_expect_related failed (%d)\n", rc); ++ } ++ } ++ ++ return NF_ACCEPT; ++} ++ ++/* inbound packet: server->client */ ++static int ++help_in(const struct iphdr* iph, size_t pktlen, ++ struct ip_conntrack* ct, enum ip_conntrack_info ctinfo) ++{ ++ return NF_ACCEPT; ++} ++ ++static int ++help(const struct iphdr* iph, size_t pktlen, ++ struct ip_conntrack* ct, enum ip_conntrack_info ctinfo) ++{ ++ /* tcplen not negative guarenteed by ip_conntrack_tcp.c */ ++ struct tcphdr* tcph = (void*)iph + iph->ihl * 4; ++ u_int32_t tcplen = pktlen - iph->ihl * 4; ++ ++ /* Until there's been traffic both ways, don't look in packets. */ ++ if (ctinfo != IP_CT_ESTABLISHED && ctinfo != IP_CT_ESTABLISHED + IP_CT_IS_REPLY) ++ { ++ DEBUGP("conntrackinfo = %u\n", ctinfo); ++ return NF_ACCEPT; ++ } ++ ++ /* Not whole TCP header? */ ++ if (tcplen < sizeof(struct tcphdr) || tcplen < tcph->doff * 4) ++ { ++ DEBUGP("tcplen = %u\n", (unsigned)tcplen); ++ return NF_ACCEPT; ++ } ++ ++ /* Checksum invalid? Ignore. */ ++ /* FIXME: Source route IP option packets --RR */ ++ if (tcp_v4_check(tcph, tcplen, iph->saddr, iph->daddr, ++ csum_partial((char*)tcph, tcplen, 0))) ++ { ++ DEBUGP("bad csum: %p %u %u.%u.%u.%u %u.%u.%u.%u\n", ++ tcph, tcplen, NIPQUAD(iph->saddr), NIPQUAD(iph->daddr)); ++ return NF_ACCEPT; ++ } ++ ++ switch (CTINFO2DIR(ctinfo)) ++ { ++ case IP_CT_DIR_ORIGINAL: ++ help_out(iph, pktlen, ct, ctinfo); ++ break; ++ case IP_CT_DIR_REPLY: ++ help_in(iph, pktlen, ct, ctinfo); ++ break; ++ } ++ ++ return NF_ACCEPT; ++} ++ ++static struct ip_conntrack_helper rtsp_helpers[MAX_PORTS]; ++static char rtsp_names[MAX_PORTS][10]; ++ ++/* This function is intentionally _NOT_ defined as __exit */ ++static void ++fini(void) ++{ ++ int i; ++ for (i = 0; i < num_ports; i++) ++ { ++ DEBUGP("unregistering port %d\n", ports[i]); ++ ip_conntrack_helper_unregister(&rtsp_helpers[i]); ++ } ++} ++ ++static int __init ++init(void) ++{ ++ int i, ret; ++ struct ip_conntrack_helper *hlpr; ++ char *tmpname; ++ ++ printk("ip_conntrack_rtsp v" IP_NF_RTSP_VERSION " loading\n"); ++ ++ if (max_outstanding < 1) ++ { ++ printk("ip_conntrack_rtsp: max_outstanding must be a positive integer\n"); ++ return -EBUSY; ++ } ++ if (setup_timeout < 0) ++ { ++ printk("ip_conntrack_rtsp: setup_timeout must be a positive integer\n"); ++ return -EBUSY; ++ } ++ ++ /* If no port given, default to standard rtsp port */ ++ if (ports[0] == 0) ++ { ++ ports[0] = RTSP_PORT; ++ } ++ ++ for (i = 0; (i < MAX_PORTS) && ports[i]; i++) ++ { ++ hlpr = &rtsp_helpers[i]; ++ memset(hlpr, 0, sizeof(struct ip_conntrack_helper)); ++ hlpr->tuple.src.u.tcp.port = htons(ports[i]); ++ hlpr->tuple.dst.protonum = IPPROTO_TCP; ++ hlpr->mask.src.u.tcp.port = 0xFFFF; ++ hlpr->mask.dst.protonum = 0xFFFF; ++ hlpr->max_expected = max_outstanding; ++ hlpr->timeout = setup_timeout; ++ hlpr->flags = IP_CT_HELPER_F_REUSE_EXPECT; ++ hlpr->me = ip_conntrack_rtsp; ++ hlpr->help = help; ++ ++ tmpname = &rtsp_names[i][0]; ++ if (ports[i] == RTSP_PORT) ++ { ++ sprintf(tmpname, "rtsp"); ++ } ++ else ++ { ++ sprintf(tmpname, "rtsp-%d", i); ++ } ++ hlpr->name = tmpname; ++ ++ DEBUGP("port #%d: %d\n", i, ports[i]); ++ ++ ret = ip_conntrack_helper_register(hlpr); ++ ++ if (ret) ++ { ++ printk("ip_conntrack_rtsp: ERROR registering port %d\n", ports[i]); ++ fini(); ++ return -EBUSY; ++ } ++ num_ports++; ++ } ++ return 0; ++} ++ ++#ifdef CONFIG_IP_NF_NAT_NEEDED ++EXPORT_SYMBOL(ip_rtsp_lock); ++#endif ++ ++module_init(init); ++module_exit(fini); +diff -urN linux-2.4.30/net/ipv4/netfilter/ip_nat_rtsp.c linux-2.4.30.new/net/ipv4/netfilter/ip_nat_rtsp.c +--- linux-2.4.30/net/ipv4/netfilter/ip_nat_rtsp.c 1970-01-01 01:00:00.000000000 +0100 ++++ linux-2.4.30.new/net/ipv4/netfilter/ip_nat_rtsp.c 2006-02-07 15:46:07.000000000 +0100 +@@ -0,0 +1,621 @@ ++/* ++ * RTSP extension for TCP NAT alteration ++ * (C) 2003 by Tom Marshall ++ * based on ip_nat_irc.c ++ * ++ * This program is free software; you can redistribute it and/or ++ * modify it under the terms of the GNU General Public License ++ * as published by the Free Software Foundation; either version ++ * 2 of the License, or (at your option) any later version. ++ * ++ * Module load syntax: ++ * insmod ip_nat_rtsp.o ports=port1,port2,...port ++ * stunaddr=
++ * destaction=[auto|strip|none] ++ * ++ * If no ports are specified, the default will be port 554 only. ++ * ++ * stunaddr specifies the address used to detect that a client is using STUN. ++ * If this address is seen in the destination parameter, it is assumed that ++ * the client has already punched a UDP hole in the firewall, so we don't ++ * mangle the client_port. If none is specified, it is autodetected. It ++ * only needs to be set if you have multiple levels of NAT. It should be ++ * set to the external address that the STUN clients detect. Note that in ++ * this case, it will not be possible for clients to use UDP with servers ++ * between the NATs. ++ * ++ * If no destaction is specified, auto is used. ++ * destaction=auto: strip destination parameter if it is not stunaddr. ++ * destaction=strip: always strip destination parameter (not recommended). ++ * destaction=none: do not touch destination parameter (not recommended). ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include ++#include ++#define NF_NEED_STRNCASECMP ++#define NF_NEED_STRTOU16 ++#include ++#define NF_NEED_MIME_NEXTLINE ++#include ++ ++#define INFOP(fmt, args...) printk(KERN_INFO "%s: %s: " fmt, __FILE__, __FUNCTION__ , ## args) ++#ifdef IP_NF_RTSP_DEBUG ++#define DEBUGP(fmt, args...) printk(KERN_DEBUG "%s: %s: " fmt, __FILE__, __FUNCTION__ , ## args) ++#else ++#define DEBUGP(fmt, args...) ++#endif ++ ++#define MAX_PORTS 8 ++#define DSTACT_AUTO 0 ++#define DSTACT_STRIP 1 ++#define DSTACT_NONE 2 ++ ++static int ports[MAX_PORTS]; ++static char* stunaddr = NULL; ++static char* destaction = NULL; ++ ++static int num_ports = 0; ++static u_int32_t extip = 0; ++static int dstact = 0; ++ ++MODULE_AUTHOR("Tom Marshall "); ++MODULE_DESCRIPTION("RTSP network address translation module"); ++MODULE_LICENSE("GPL"); ++#ifdef MODULE_PARM ++MODULE_PARM(ports, "1-" __MODULE_STRING(MAX_PORTS) "i"); ++MODULE_PARM_DESC(ports, "port numbers of RTSP servers"); ++MODULE_PARM(stunaddr, "s"); ++MODULE_PARM_DESC(stunaddr, "Address for detecting STUN"); ++MODULE_PARM(destaction, "s"); ++MODULE_PARM_DESC(destaction, "Action for destination parameter (auto/strip/none)"); ++#endif ++ ++/* protects rtsp part of conntracks */ ++DECLARE_LOCK_EXTERN(ip_rtsp_lock); ++ ++#define SKIP_WSPACE(ptr,len,off) while(off < len && isspace(*(ptr+off))) { off++; } ++ ++/*** helper functions ***/ ++ ++static void ++get_skb_tcpdata(struct sk_buff* skb, char** pptcpdata, uint* ptcpdatalen) ++{ ++ struct iphdr* iph = (struct iphdr*)skb->nh.iph; ++ struct tcphdr* tcph = (struct tcphdr*)((char*)iph + iph->ihl*4); ++ ++ *pptcpdata = (char*)tcph + tcph->doff*4; ++ *ptcpdatalen = ((char*)skb->h.raw + skb->len) - *pptcpdata; ++} ++ ++/*** nat functions ***/ ++ ++/* ++ * Mangle the "Transport:" header: ++ * - Replace all occurences of "client_port=" ++ * - Handle destination parameter ++ * ++ * In: ++ * ct, ctinfo = conntrack context ++ * pskb = packet ++ * tranoff = Transport header offset from TCP data ++ * tranlen = Transport header length (incl. CRLF) ++ * rport_lo = replacement low port (host endian) ++ * rport_hi = replacement high port (host endian) ++ * ++ * Returns packet size difference. ++ * ++ * Assumes that a complete transport header is present, ending with CR or LF ++ */ ++static int ++rtsp_mangle_tran(struct ip_conntrack* ct, enum ip_conntrack_info ctinfo, ++ struct ip_conntrack_expect* exp, ++ struct sk_buff** pskb, uint tranoff, uint tranlen) ++{ ++ char* ptcp; ++ uint tcplen; ++ char* ptran; ++ char rbuf1[16]; /* Replacement buffer (one port) */ ++ uint rbuf1len; /* Replacement len (one port) */ ++ char rbufa[16]; /* Replacement buffer (all ports) */ ++ uint rbufalen; /* Replacement len (all ports) */ ++ u_int32_t newip; ++ u_int16_t loport, hiport; ++ uint off = 0; ++ uint diff; /* Number of bytes we removed */ ++ ++ struct ip_ct_rtsp_expect* prtspexp = &exp->help.exp_rtsp_info; ++ struct ip_conntrack_tuple t; ++ ++ char szextaddr[15+1]; ++ uint extaddrlen; ++ int is_stun; ++ ++ get_skb_tcpdata(*pskb, &ptcp, &tcplen); ++ ptran = ptcp+tranoff; ++ ++ if (tranoff+tranlen > tcplen || tcplen-tranoff < tranlen || ++ tranlen < 10 || !iseol(ptran[tranlen-1]) || ++ nf_strncasecmp(ptran, "Transport:", 10) != 0) ++ { ++ INFOP("sanity check failed\n"); ++ return 0; ++ } ++ off += 10; ++ SKIP_WSPACE(ptcp+tranoff, tranlen, off); ++ ++ newip = ct->tuplehash[IP_CT_DIR_REPLY].tuple.dst.ip; ++ t = exp->tuple; ++ t.dst.ip = newip; ++ ++ extaddrlen = extip ? sprintf(szextaddr, "%u.%u.%u.%u", NIPQUAD(extip)) ++ : sprintf(szextaddr, "%u.%u.%u.%u", NIPQUAD(newip)); ++ DEBUGP("stunaddr=%s (%s)\n", szextaddr, (extip?"forced":"auto")); ++ ++ rbuf1len = rbufalen = 0; ++ switch (prtspexp->pbtype) ++ { ++ case pb_single: ++ for (loport = prtspexp->loport; loport != 0; loport++) /* XXX: improper wrap? */ ++ { ++ t.dst.u.udp.port = htons(loport); ++ if (ip_conntrack_change_expect(exp, &t) == 0) ++ { ++ DEBUGP("using port %hu\n", loport); ++ break; ++ } ++ } ++ if (loport != 0) ++ { ++ rbuf1len = sprintf(rbuf1, "%hu", loport); ++ rbufalen = sprintf(rbufa, "%hu", loport); ++ } ++ break; ++ case pb_range: ++ for (loport = prtspexp->loport; loport != 0; loport += 2) /* XXX: improper wrap? */ ++ { ++ t.dst.u.udp.port = htons(loport); ++ if (ip_conntrack_change_expect(exp, &t) == 0) ++ { ++ hiport = loport + ~exp->mask.dst.u.udp.port; ++ DEBUGP("using ports %hu-%hu\n", loport, hiport); ++ break; ++ } ++ } ++ if (loport != 0) ++ { ++ rbuf1len = sprintf(rbuf1, "%hu", loport); ++ rbufalen = sprintf(rbufa, "%hu-%hu", loport, loport+1); ++ } ++ break; ++ case pb_discon: ++ for (loport = prtspexp->loport; loport != 0; loport++) /* XXX: improper wrap? */ ++ { ++ t.dst.u.udp.port = htons(loport); ++ if (ip_conntrack_change_expect(exp, &t) == 0) ++ { ++ DEBUGP("using port %hu (1 of 2)\n", loport); ++ break; ++ } ++ } ++ for (hiport = prtspexp->hiport; hiport != 0; hiport++) /* XXX: improper wrap? */ ++ { ++ t.dst.u.udp.port = htons(hiport); ++ if (ip_conntrack_change_expect(exp, &t) == 0) ++ { ++ DEBUGP("using port %hu (2 of 2)\n", hiport); ++ break; ++ } ++ } ++ if (loport != 0 && hiport != 0) ++ { ++ rbuf1len = sprintf(rbuf1, "%hu", loport); ++ if (hiport == loport+1) ++ { ++ rbufalen = sprintf(rbufa, "%hu-%hu", loport, hiport); ++ } ++ else ++ { ++ rbufalen = sprintf(rbufa, "%hu/%hu", loport, hiport); ++ } ++ } ++ break; ++ } ++ ++ if (rbuf1len == 0) ++ { ++ return 0; /* cannot get replacement port(s) */ ++ } ++ ++ /* Transport: tran;field;field=val,tran;field;field=val,... */ ++ while (off < tranlen) ++ { ++ uint saveoff; ++ const char* pparamend; ++ uint nextparamoff; ++ ++ pparamend = memchr(ptran+off, ',', tranlen-off); ++ pparamend = (pparamend == NULL) ? ptran+tranlen : pparamend+1; ++ nextparamoff = pparamend-ptcp; ++ ++ /* ++ * We pass over each param twice. On the first pass, we look for a ++ * destination= field. It is handled by the security policy. If it ++ * is present, allowed, and equal to our external address, we assume ++ * that STUN is being used and we leave the client_port= field alone. ++ */ ++ is_stun = 0; ++ saveoff = off; ++ while (off < nextparamoff) ++ { ++ const char* pfieldend; ++ uint nextfieldoff; ++ ++ pfieldend = memchr(ptran+off, ';', nextparamoff-off); ++ nextfieldoff = (pfieldend == NULL) ? nextparamoff : pfieldend-ptran+1; ++ ++ if (dstact != DSTACT_NONE && strncmp(ptran+off, "destination=", 12) == 0) ++ { ++ if (strncmp(ptran+off+12, szextaddr, extaddrlen) == 0) ++ { ++ is_stun = 1; ++ } ++ if (dstact == DSTACT_STRIP || (dstact == DSTACT_AUTO && !is_stun)) ++ { ++ diff = nextfieldoff-off; ++ if (!ip_nat_mangle_tcp_packet(pskb, ct, ctinfo, ++ off, diff, NULL, 0)) ++ { ++ /* mangle failed, all we can do is bail */ ++ return 0; ++ } ++ get_skb_tcpdata(*pskb, &ptcp, &tcplen); ++ ptran = ptcp+tranoff; ++ tranlen -= diff; ++ nextparamoff -= diff; ++ nextfieldoff -= diff; ++ } ++ } ++ ++ off = nextfieldoff; ++ } ++ if (is_stun) ++ { ++ continue; ++ } ++ off = saveoff; ++ while (off < nextparamoff) ++ { ++ const char* pfieldend; ++ uint nextfieldoff; ++ ++ pfieldend = memchr(ptran+off, ';', nextparamoff-off); ++ nextfieldoff = (pfieldend == NULL) ? nextparamoff : pfieldend-ptran+1; ++ ++ if (strncmp(ptran+off, "client_port=", 12) == 0) ++ { ++ u_int16_t port; ++ uint numlen; ++ uint origoff; ++ uint origlen; ++ char* rbuf = rbuf1; ++ uint rbuflen = rbuf1len; ++ ++ off += 12; ++ origoff = (ptran-ptcp)+off; ++ origlen = 0; ++ numlen = nf_strtou16(ptran+off, &port); ++ off += numlen; ++ origlen += numlen; ++ if (port != prtspexp->loport) ++ { ++ DEBUGP("multiple ports found, port %hu ignored\n", port); ++ } ++ else ++ { ++ if (ptran[off] == '-' || ptran[off] == '/') ++ { ++ off++; ++ origlen++; ++ numlen = nf_strtou16(ptran+off, &port); ++ off += numlen; ++ origlen += numlen; ++ rbuf = rbufa; ++ rbuflen = rbufalen; ++ } ++ ++ /* ++ * note we cannot just memcpy() if the sizes are the same. ++ * the mangle function does skb resizing, checks for a ++ * cloned skb, and updates the checksums. ++ * ++ * parameter 4 below is offset from start of tcp data. ++ */ ++ diff = origlen-rbuflen; ++ if (!ip_nat_mangle_tcp_packet(pskb, ct, ctinfo, ++ origoff, origlen, rbuf, rbuflen)) ++ { ++ /* mangle failed, all we can do is bail */ ++ return 0; ++ } ++ get_skb_tcpdata(*pskb, &ptcp, &tcplen); ++ ptran = ptcp+tranoff; ++ tranlen -= diff; ++ nextparamoff -= diff; ++ nextfieldoff -= diff; ++ } ++ } ++ ++ off = nextfieldoff; ++ } ++ ++ off = nextparamoff; ++ } ++ ++ return 1; ++} ++ ++static unsigned int ++expected(struct sk_buff **pskb, uint hooknum, struct ip_conntrack* ct, struct ip_nat_info* info) ++{ ++ struct ip_nat_multi_range mr; ++ u_int32_t newdstip, newsrcip, newip; ++ ++ struct ip_conntrack *master = master_ct(ct); ++ ++ IP_NF_ASSERT(info); ++ IP_NF_ASSERT(master); ++ ++ IP_NF_ASSERT(!(info->initialized & (1 << HOOK2MANIP(hooknum)))); ++ ++ newdstip = master->tuplehash[IP_CT_DIR_ORIGINAL].tuple.src.ip; ++ newsrcip = ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple.src.ip; ++ newip = (HOOK2MANIP(hooknum) == IP_NAT_MANIP_SRC) ? newsrcip : newdstip; ++ ++ DEBUGP("newsrcip=%u.%u.%u.%u, newdstip=%u.%u.%u.%u, newip=%u.%u.%u.%u\n", ++ NIPQUAD(newsrcip), NIPQUAD(newdstip), NIPQUAD(newip)); ++ ++ mr.rangesize = 1; ++ /* We don't want to manip the per-protocol, just the IPs. */ ++ mr.range[0].flags = IP_NAT_RANGE_MAP_IPS; ++ mr.range[0].min_ip = mr.range[0].max_ip = newip; ++ ++ return ip_nat_setup_info(ct, &mr, hooknum); ++} ++ ++static uint ++help_out(struct ip_conntrack* ct, enum ip_conntrack_info ctinfo, ++ struct ip_conntrack_expect* exp, struct sk_buff** pskb) ++{ ++ char* ptcp; ++ uint tcplen; ++ uint hdrsoff; ++ uint hdrslen; ++ uint lineoff; ++ uint linelen; ++ uint off; ++ ++ struct iphdr* iph = (struct iphdr*)(*pskb)->nh.iph; ++ struct tcphdr* tcph = (struct tcphdr*)((void*)iph + iph->ihl*4); ++ ++ struct ip_ct_rtsp_expect* prtspexp = &exp->help.exp_rtsp_info; ++ ++ get_skb_tcpdata(*pskb, &ptcp, &tcplen); ++ ++ hdrsoff = exp->seq - ntohl(tcph->seq); ++ hdrslen = prtspexp->len; ++ off = hdrsoff; ++ ++ while (nf_mime_nextline(ptcp, hdrsoff+hdrslen, &off, &lineoff, &linelen)) ++ { ++ if (linelen == 0) ++ { ++ break; ++ } ++ if (off > hdrsoff+hdrslen) ++ { ++ INFOP("!! overrun !!"); ++ break; ++ } ++ DEBUGP("hdr: len=%u, %.*s", linelen, (int)linelen, ptcp+lineoff); ++ ++ if (nf_strncasecmp(ptcp+lineoff, "Transport:", 10) == 0) ++ { ++ uint oldtcplen = tcplen; ++ if (!rtsp_mangle_tran(ct, ctinfo, exp, pskb, lineoff, linelen)) ++ { ++ break; ++ } ++ get_skb_tcpdata(*pskb, &ptcp, &tcplen); ++ hdrslen -= (oldtcplen-tcplen); ++ off -= (oldtcplen-tcplen); ++ lineoff -= (oldtcplen-tcplen); ++ linelen -= (oldtcplen-tcplen); ++ DEBUGP("rep: len=%u, %.*s", linelen, (int)linelen, ptcp+lineoff); ++ } ++ } ++ ++ return NF_ACCEPT; ++} ++ ++static uint ++help_in(struct ip_conntrack* ct, enum ip_conntrack_info ctinfo, ++ struct ip_conntrack_expect* exp, struct sk_buff** pskb) ++{ ++ /* XXX: unmangle */ ++ return NF_ACCEPT; ++} ++ ++static uint ++help(struct ip_conntrack* ct, ++ struct ip_conntrack_expect* exp, ++ struct ip_nat_info* info, ++ enum ip_conntrack_info ctinfo, ++ unsigned int hooknum, ++ struct sk_buff** pskb) ++{ ++ struct iphdr* iph = (struct iphdr*)(*pskb)->nh.iph; ++ struct tcphdr* tcph = (struct tcphdr*)((char*)iph + iph->ihl * 4); ++ uint datalen; ++ int dir; ++ struct ip_ct_rtsp_expect* ct_rtsp_info; ++ int rc = NF_ACCEPT; ++ ++ if (ct == NULL || exp == NULL || info == NULL || pskb == NULL) ++ { ++ DEBUGP("!! null ptr (%p,%p,%p,%p) !!\n", ct, exp, info, pskb); ++ return NF_ACCEPT; ++ } ++ ++ ct_rtsp_info = &exp->help.exp_rtsp_info; ++ ++ /* ++ * Only mangle things once: original direction in POST_ROUTING ++ * and reply direction on PRE_ROUTING. ++ */ ++ dir = CTINFO2DIR(ctinfo); ++ if (!((hooknum == NF_IP_POST_ROUTING && dir == IP_CT_DIR_ORIGINAL) ++ || (hooknum == NF_IP_PRE_ROUTING && dir == IP_CT_DIR_REPLY))) ++ { ++ DEBUGP("Not touching dir %s at hook %s\n", ++ dir == IP_CT_DIR_ORIGINAL ? "ORIG" : "REPLY", ++ hooknum == NF_IP_POST_ROUTING ? "POSTROUTING" ++ : hooknum == NF_IP_PRE_ROUTING ? "PREROUTING" ++ : hooknum == NF_IP_LOCAL_OUT ? "OUTPUT" : "???"); ++ return NF_ACCEPT; ++ } ++ DEBUGP("got beyond not touching\n"); ++ ++ datalen = (*pskb)->len - iph->ihl * 4 - tcph->doff * 4; ++ ++ LOCK_BH(&ip_rtsp_lock); ++ /* Ensure the packet contains all of the marked data */ ++ if (!between(exp->seq + ct_rtsp_info->len, ++ ntohl(tcph->seq), ntohl(tcph->seq) + datalen)) ++ { ++ /* Partial retransmission? Probably a hacker. */ ++ if (net_ratelimit()) ++ { ++ INFOP("partial packet %u/%u in %u/%u\n", ++ exp->seq, ct_rtsp_info->len, ntohl(tcph->seq), ntohl(tcph->seq) + datalen); ++ } ++ UNLOCK_BH(&ip_rtsp_lock); ++ return NF_DROP; ++ } ++ ++ switch (dir) ++ { ++ case IP_CT_DIR_ORIGINAL: ++ rc = help_out(ct, ctinfo, exp, pskb); ++ break; ++ case IP_CT_DIR_REPLY: ++ rc = help_in(ct, ctinfo, exp, pskb); ++ break; ++ } ++ UNLOCK_BH(&ip_rtsp_lock); ++ ++ return rc; ++} ++ ++static struct ip_nat_helper ip_nat_rtsp_helpers[MAX_PORTS]; ++static char rtsp_names[MAX_PORTS][10]; ++ ++/* This function is intentionally _NOT_ defined as __exit */ ++static void ++fini(void) ++{ ++ int i; ++ ++ for (i = 0; i < num_ports; i++) ++ { ++ DEBUGP("unregistering helper for port %d\n", ports[i]); ++ ip_nat_helper_unregister(&ip_nat_rtsp_helpers[i]); ++ } ++} ++ ++static int __init ++init(void) ++{ ++ int ret = 0; ++ int i; ++ struct ip_nat_helper* hlpr; ++ char* tmpname; ++ ++ printk("ip_nat_rtsp v" IP_NF_RTSP_VERSION " loading\n"); ++ ++ if (ports[0] == 0) ++ { ++ ports[0] = RTSP_PORT; ++ } ++ ++ for (i = 0; (i < MAX_PORTS) && ports[i] != 0; i++) ++ { ++ hlpr = &ip_nat_rtsp_helpers[i]; ++ memset(hlpr, 0, sizeof(struct ip_nat_helper)); ++ ++ hlpr->tuple.dst.protonum = IPPROTO_TCP; ++ hlpr->tuple.src.u.tcp.port = htons(ports[i]); ++ hlpr->mask.src.u.tcp.port = 0xFFFF; ++ hlpr->mask.dst.protonum = 0xFFFF; ++ hlpr->help = help; ++ hlpr->flags = 0; ++ hlpr->me = THIS_MODULE; ++ hlpr->expect = expected; ++ ++ tmpname = &rtsp_names[i][0]; ++ if (ports[i] == RTSP_PORT) ++ { ++ sprintf(tmpname, "rtsp"); ++ } ++ else ++ { ++ sprintf(tmpname, "rtsp-%d", i); ++ } ++ hlpr->name = tmpname; ++ ++ DEBUGP("registering helper for port %d: name %s\n", ports[i], hlpr->name); ++ ret = ip_nat_helper_register(hlpr); ++ ++ if (ret) ++ { ++ printk("ip_nat_rtsp: error registering helper for port %d\n", ports[i]); ++ fini(); ++ return 1; ++ } ++ num_ports++; ++ } ++ if (stunaddr != NULL) ++ { ++ extip = in_aton(stunaddr); ++ } ++ if (destaction != NULL) ++ { ++ if (strcmp(destaction, "auto") == 0) ++ { ++ dstact = DSTACT_AUTO; ++ } ++ if (strcmp(destaction, "strip") == 0) ++ { ++ dstact = DSTACT_STRIP; ++ } ++ if (strcmp(destaction, "none") == 0) ++ { ++ dstact = DSTACT_NONE; ++ } ++ } ++ return ret; ++} ++ ++module_init(init); ++module_exit(fini); +diff -urN linux-2.4.30/net/ipv4/netfilter/Makefile linux-2.4.30.new/net/ipv4/netfilter/Makefile +--- linux-2.4.30/net/ipv4/netfilter/Makefile 2006-02-07 15:44:46.000000000 +0100 ++++ linux-2.4.30.new/net/ipv4/netfilter/Makefile 2006-02-07 15:46:07.000000000 +0100 +@@ -32,6 +32,14 @@ + obj-$(CONFIG_IP_NF_CONNTRACK) += ip_conntrack.o + + # connection tracking helpers ++ ++# rtsp protocol support ++obj-$(CONFIG_IP_NF_RTSP) += ip_conntrack_rtsp.o ++ifdef CONFIG_IP_NF_NAT_RTSP ++ export-objs += ip_conntrack_rtsp.o ++endif ++obj-$(CONFIG_IP_NF_NAT_RTSP) += ip_nat_rtsp.o ++ + obj-$(CONFIG_IP_NF_AMANDA) += ip_conntrack_amanda.o + ifdef CONFIG_IP_NF_AMANDA + export-objs += ip_conntrack_amanda.o +diff -urN linux-2.4.30/include/linux/netfilter_ipv4/ip_conntrack.h linux-2.4.30.new/include/linux/netfilter_ipv4/ip_conntrack.h +--- linux-2.4.30/include/linux/netfilter_ipv4/ip_conntrack.h 2006-02-07 15:44:46.000000000 +0100 ++++ linux-2.4.30.new/include/linux/netfilter_ipv4/ip_conntrack.h 2006-02-07 15:46:07.000000000 +0100 +@@ -66,6 +66,7 @@ + }; + + /* Add protocol helper include file here */ ++#include + #include + + #include +@@ -77,6 +78,7 @@ + /* per expectation: application helper private data */ + union ip_conntrack_expect_help { + /* insert conntrack helper private data (expect) here */ ++ struct ip_ct_rtsp_expect exp_rtsp_info; + struct ip_ct_amanda_expect exp_amanda_info; + struct ip_ct_ftp_expect exp_ftp_info; + struct ip_ct_irc_expect exp_irc_info; +@@ -94,6 +96,7 @@ + /* per conntrack: application helper private data */ + union ip_conntrack_help { + /* insert conntrack helper private data (master) here */ ++ struct ip_ct_rtsp_master ct_rtsp_info; + struct ip_ct_ftp_master ct_ftp_info; + struct ip_ct_irc_master ct_irc_info; + struct ip_ct_pptp_master ct_pptp_info; +diff -urN linux-2.4.30/include/linux/netfilter_ipv4/ip_conntrack.h.orig linux-2.4.30.new/include/linux/netfilter_ipv4/ip_conntrack.h.orig +--- linux-2.4.30/include/linux/netfilter_ipv4/ip_conntrack.h.orig 1970-01-01 01:00:00.000000000 +0100 ++++ linux-2.4.30.new/include/linux/netfilter_ipv4/ip_conntrack.h.orig 2006-02-07 15:42:53.000000000 +0100 +@@ -0,0 +1,297 @@ ++#ifndef _IP_CONNTRACK_H ++#define _IP_CONNTRACK_H ++/* Connection state tracking for netfilter. This is separated from, ++ but required by, the NAT layer; it can also be used by an iptables ++ extension. */ ++ ++#include ++#include ++#include ++#include ++ ++enum ip_conntrack_info ++{ ++ /* Part of an established connection (either direction). */ ++ IP_CT_ESTABLISHED, ++ ++ /* Like NEW, but related to an existing connection, or ICMP error ++ (in either direction). */ ++ IP_CT_RELATED, ++ ++ /* Started a new connection to track (only ++ IP_CT_DIR_ORIGINAL); may be a retransmission. */ ++ IP_CT_NEW, ++ ++ /* >= this indicates reply direction */ ++ IP_CT_IS_REPLY, ++ ++ /* Number of distinct IP_CT types (no NEW in reply dirn). */ ++ IP_CT_NUMBER = IP_CT_IS_REPLY * 2 - 1 ++}; ++ ++/* Bitset representing status of connection. */ ++enum ip_conntrack_status { ++ /* It's an expected connection: bit 0 set. This bit never changed */ ++ IPS_EXPECTED_BIT = 0, ++ IPS_EXPECTED = (1 << IPS_EXPECTED_BIT), ++ ++ /* We've seen packets both ways: bit 1 set. Can be set, not unset. */ ++ IPS_SEEN_REPLY_BIT = 1, ++ IPS_SEEN_REPLY = (1 << IPS_SEEN_REPLY_BIT), ++ ++ /* Conntrack should never be early-expired. */ ++ IPS_ASSURED_BIT = 2, ++ IPS_ASSURED = (1 << IPS_ASSURED_BIT), ++ ++ /* Connection is confirmed: originating packet has left box */ ++ IPS_CONFIRMED_BIT = 3, ++ IPS_CONFIRMED = (1 << IPS_CONFIRMED_BIT), ++}; ++ ++#include ++#include ++#include ++ ++/* per conntrack: protocol private data */ ++union ip_conntrack_proto { ++ /* insert conntrack proto private data here */ ++ struct ip_ct_tcp tcp; ++ struct ip_ct_icmp icmp; ++ struct ip_ct_gre gre; ++}; ++ ++union ip_conntrack_expect_proto { ++ /* insert expect proto private data here */ ++ struct ip_ct_gre_expect gre; ++}; ++ ++/* Add protocol helper include file here */ ++#include ++ ++#include ++#include ++#include ++#include ++#include ++ ++/* per expectation: application helper private data */ ++union ip_conntrack_expect_help { ++ /* insert conntrack helper private data (expect) here */ ++ struct ip_ct_amanda_expect exp_amanda_info; ++ struct ip_ct_ftp_expect exp_ftp_info; ++ struct ip_ct_irc_expect exp_irc_info; ++ struct ip_ct_pptp_expect exp_pptp_info; ++ struct ip_ct_sip_expect exp_sip_info; ++ struct ip_ct_h225_expect exp_h225_info; ++ ++#ifdef CONFIG_IP_NF_NAT_NEEDED ++ union { ++ /* insert nat helper private data (expect) here */ ++ } nat; ++#endif ++}; ++ ++/* per conntrack: application helper private data */ ++union ip_conntrack_help { ++ /* insert conntrack helper private data (master) here */ ++ struct ip_ct_ftp_master ct_ftp_info; ++ struct ip_ct_irc_master ct_irc_info; ++ struct ip_ct_pptp_master ct_pptp_info; ++ struct ip_ct_sip_master ct_sip_info; ++ struct ip_ct_h225_master ct_h225_info; ++}; ++ ++#ifdef CONFIG_IP_NF_NAT_NEEDED ++#include ++#include ++ ++/* per conntrack: nat application helper private data */ ++union ip_conntrack_nat_help { ++ /* insert nat helper private data here */ ++ struct ip_nat_pptp nat_pptp_info; ++}; ++#endif ++ ++#ifdef __KERNEL__ ++ ++#include ++#include ++ ++#ifdef CONFIG_NETFILTER_DEBUG ++#define IP_NF_ASSERT(x) \ ++do { \ ++ if (!(x)) \ ++ /* Wooah! I'm tripping my conntrack in a frenzy of \ ++ netplay... */ \ ++ printk("NF_IP_ASSERT: %s:%i(%s)\n", \ ++ __FILE__, __LINE__, __FUNCTION__); \ ++} while(0) ++#else ++#define IP_NF_ASSERT(x) ++#endif ++ ++struct ip_conntrack_expect ++{ ++ /* Internal linked list (global expectation list) */ ++ struct list_head list; ++ ++ /* reference count */ ++ atomic_t use; ++ ++ /* expectation list for this master */ ++ struct list_head expected_list; ++ ++ /* The conntrack of the master connection */ ++ struct ip_conntrack *expectant; ++ ++ /* The conntrack of the sibling connection, set after ++ * expectation arrived */ ++ struct ip_conntrack *sibling; ++ ++ /* Tuple saved for conntrack */ ++ struct ip_conntrack_tuple ct_tuple; ++ ++ /* Timer function; deletes the expectation. */ ++ struct timer_list timeout; ++ ++ /* Data filled out by the conntrack helpers follow: */ ++ ++ /* We expect this tuple, with the following mask */ ++ struct ip_conntrack_tuple tuple, mask; ++ ++ /* Function to call after setup and insertion */ ++ int (*expectfn)(struct ip_conntrack *new); ++ ++ /* At which sequence number did this expectation occur */ ++ u_int32_t seq; ++ ++ union ip_conntrack_expect_proto proto; ++ ++ union ip_conntrack_expect_help help; ++}; ++ ++struct ip_conntrack_helper; ++ ++struct ip_conntrack ++{ ++ /* Usage count in here is 1 for hash table/destruct timer, 1 per skb, ++ plus 1 for any connection(s) we are `master' for */ ++ struct nf_conntrack ct_general; ++ ++ /* These are my tuples; original and reply */ ++ struct ip_conntrack_tuple_hash tuplehash[IP_CT_DIR_MAX]; ++ ++ /* Have we seen traffic both ways yet? (bitset) */ ++ unsigned long status; ++ ++ /* Timer function; drops refcnt when it goes off. */ ++ struct timer_list timeout; ++ ++ /* If we're expecting another related connection, this will be ++ in expected linked list */ ++ struct list_head sibling_list; ++ ++ /* Current number of expected connections */ ++ unsigned int expecting; ++ ++ /* If we were expected by an expectation, this will be it */ ++ struct ip_conntrack_expect *master; ++ ++ /* Helper, if any. */ ++ struct ip_conntrack_helper *helper; ++ ++ /* Our various nf_ct_info structs specify *what* relation this ++ packet has to the conntrack */ ++ struct nf_ct_info infos[IP_CT_NUMBER]; ++ ++ /* Storage reserved for other modules: */ ++ ++ union ip_conntrack_proto proto; ++ ++ union ip_conntrack_help help; ++ ++#ifdef CONFIG_IP_NF_NAT_NEEDED ++ struct { ++ struct ip_nat_info info; ++ union ip_conntrack_nat_help help; ++#if defined(CONFIG_IP_NF_TARGET_MASQUERADE) || \ ++ defined(CONFIG_IP_NF_TARGET_MASQUERADE_MODULE) ++ int masq_index; ++#endif ++ } nat; ++#endif /* CONFIG_IP_NF_NAT_NEEDED */ ++ ++#if defined(CONFIG_IP_NF_MATCH_LAYER7) || defined(CONFIG_IP_NF_MATCH_LAYER7_MODULE) ++ struct { ++ unsigned int numpackets; /* surely this is kept track of somewhere else, right? I can't find it... */ ++ char * app_proto; /* "http", "ftp", etc. NULL if unclassifed */ ++ ++ /* the application layer data so far. NULL if ->numpackets > numpackets */ ++ char * app_data; ++ ++ unsigned int app_data_len; ++ } layer7; ++#endif ++#if defined(CONFIG_IP_NF_CONNTRACK_MARK) ++ unsigned long mark; ++#endif ++}; ++ ++/* get master conntrack via master expectation */ ++#define master_ct(conntr) (conntr->master ? conntr->master->expectant : NULL) ++ ++/* Alter reply tuple (maybe alter helper). If it's already taken, ++ return 0 and don't do alteration. */ ++extern int ++ip_conntrack_alter_reply(struct ip_conntrack *conntrack, ++ const struct ip_conntrack_tuple *newreply); ++ ++/* Is this tuple taken? (ignoring any belonging to the given ++ conntrack). */ ++extern int ++ip_conntrack_tuple_taken(const struct ip_conntrack_tuple *tuple, ++ const struct ip_conntrack *ignored_conntrack); ++ ++/* Return conntrack_info and tuple hash for given skb. */ ++extern struct ip_conntrack * ++ip_conntrack_get(struct sk_buff *skb, enum ip_conntrack_info *ctinfo); ++ ++/* decrement reference count on a conntrack */ ++extern inline void ip_conntrack_put(struct ip_conntrack *ct); ++ ++/* find unconfirmed expectation based on tuple */ ++struct ip_conntrack_expect * ++ip_conntrack_expect_find_get(const struct ip_conntrack_tuple *tuple); ++ ++/* decrement reference count on an expectation */ ++void ip_conntrack_expect_put(struct ip_conntrack_expect *exp); ++ ++extern int invert_tuplepr(struct ip_conntrack_tuple *inverse, ++ const struct ip_conntrack_tuple *orig); ++ ++/* Refresh conntrack for this many jiffies */ ++extern void ip_ct_refresh(struct ip_conntrack *ct, ++ unsigned long extra_jiffies); ++ ++/* These are for NAT. Icky. */ ++/* Call me when a conntrack is destroyed. */ ++extern void (*ip_conntrack_destroyed)(struct ip_conntrack *conntrack); ++ ++/* Returns new sk_buff, or NULL */ ++struct sk_buff * ++ip_ct_gather_frags(struct sk_buff *skb, u_int32_t user); ++ ++/* Iterate over all conntracks: if iter returns true, it's deleted. */ ++extern void ++ip_ct_iterate_cleanup(int (*iter)(struct ip_conntrack *i, void *data), ++ void *data); ++ ++/* It's confirmed if it is, or has been in the hash table. */ ++static inline int is_confirmed(struct ip_conntrack *ct) ++{ ++ return test_bit(IPS_CONFIRMED_BIT, &ct->status); ++} ++ ++extern unsigned int ip_conntrack_htable_size; ++#endif /* __KERNEL__ */ ++#endif /* _IP_CONNTRACK_H */ +diff -urN linux-2.4.30/include/linux/netfilter_ipv4/ip_conntrack_rtsp.h linux-2.4.30.new/include/linux/netfilter_ipv4/ip_conntrack_rtsp.h +--- linux-2.4.30/include/linux/netfilter_ipv4/ip_conntrack_rtsp.h 1970-01-01 01:00:00.000000000 +0100 ++++ linux-2.4.30.new/include/linux/netfilter_ipv4/ip_conntrack_rtsp.h 2006-02-07 15:46:07.000000000 +0100 +@@ -0,0 +1,68 @@ ++/* ++ * RTSP extension for IP connection tracking. ++ * (C) 2003 by Tom Marshall ++ * based on ip_conntrack_irc.h ++ * ++ * This program is free software; you can redistribute it and/or ++ * modify it under the terms of the GNU General Public License ++ * as published by the Free Software Foundation; either version ++ * 2 of the License, or (at your option) any later version. ++ */ ++#ifndef _IP_CONNTRACK_RTSP_H ++#define _IP_CONNTRACK_RTSP_H ++ ++/* #define IP_NF_RTSP_DEBUG */ ++#define IP_NF_RTSP_VERSION "0.01" ++ ++/* port block types */ ++typedef enum { ++ pb_single, /* client_port=x */ ++ pb_range, /* client_port=x-y */ ++ pb_discon /* client_port=x/y (rtspbis) */ ++} portblock_t; ++ ++/* We record seq number and length of rtsp headers here, all in host order. */ ++ ++/* ++ * This structure is per expected connection. It is a member of struct ++ * ip_conntrack_expect. The TCP SEQ for the conntrack expect is stored ++ * there and we are expected to only store the length of the data which ++ * needs replaced. If a packet contains multiple RTSP messages, we create ++ * one expected connection per message. ++ * ++ * We use these variables to mark the entire header block. This may seem ++ * like overkill, but the nature of RTSP requires it. A header may appear ++ * multiple times in a message. We must treat two Transport headers the ++ * same as one Transport header with two entries. ++ */ ++struct ip_ct_rtsp_expect ++{ ++ u_int32_t len; /* length of header block */ ++ portblock_t pbtype; /* Type of port block that was requested */ ++ u_int16_t loport; /* Port that was requested, low or first */ ++ u_int16_t hiport; /* Port that was requested, high or second */ ++#if 0 ++ uint method; /* RTSP method */ ++ uint cseq; /* CSeq from request */ ++#endif ++}; ++ ++/* This structure exists only once per master */ ++struct ip_ct_rtsp_master ++{ ++ /* Empty (?) */ ++}; ++ ++ ++#ifdef __KERNEL__ ++ ++#include ++ ++#define RTSP_PORT 554 ++ ++/* Protects rtsp part of conntracks */ ++DECLARE_LOCK_EXTERN(ip_rtsp_lock); ++ ++#endif /* __KERNEL__ */ ++ ++#endif /* _IP_CONNTRACK_RTSP_H */ +diff -urN linux-2.4.30/include/linux/netfilter_helpers.h linux-2.4.30.new/include/linux/netfilter_helpers.h +--- linux-2.4.30/include/linux/netfilter_helpers.h 1970-01-01 01:00:00.000000000 +0100 ++++ linux-2.4.30.new/include/linux/netfilter_helpers.h 2006-02-07 15:46:07.000000000 +0100 +@@ -0,0 +1,133 @@ ++/* ++ * Helpers for netfiler modules. This file provides implementations for basic ++ * functions such as strncasecmp(), etc. ++ * ++ * gcc will warn for defined but unused functions, so we only include the ++ * functions requested. The following macros are used: ++ * NF_NEED_STRNCASECMP nf_strncasecmp() ++ * NF_NEED_STRTOU16 nf_strtou16() ++ * NF_NEED_STRTOU32 nf_strtou32() ++ */ ++#ifndef _NETFILTER_HELPERS_H ++#define _NETFILTER_HELPERS_H ++ ++/* Only include these functions for kernel code. */ ++#ifdef __KERNEL__ ++ ++#include ++#define iseol(c) ( (c) == '\r' || (c) == '\n' ) ++ ++/* ++ * The standard strncasecmp() ++ */ ++#ifdef NF_NEED_STRNCASECMP ++static int ++nf_strncasecmp(const char* s1, const char* s2, u_int32_t len) ++{ ++ if (s1 == NULL || s2 == NULL) ++ { ++ if (s1 == NULL && s2 == NULL) ++ { ++ return 0; ++ } ++ return (s1 == NULL) ? -1 : 1; ++ } ++ while (len > 0 && tolower(*s1) == tolower(*s2)) ++ { ++ len--; ++ s1++; ++ s2++; ++ } ++ return ( (len == 0) ? 0 : (tolower(*s1) - tolower(*s2)) ); ++} ++#endif /* NF_NEED_STRNCASECMP */ ++ ++/* ++ * Parse a string containing a 16-bit unsigned integer. ++ * Returns the number of chars used, or zero if no number is found. ++ */ ++#ifdef NF_NEED_STRTOU16 ++static int ++nf_strtou16(const char* pbuf, u_int16_t* pval) ++{ ++ int n = 0; ++ ++ *pval = 0; ++ while (isdigit(pbuf[n])) ++ { ++ *pval = (*pval * 10) + (pbuf[n] - '0'); ++ n++; ++ } ++ ++ return n; ++} ++#endif /* NF_NEED_STRTOU16 */ ++ ++/* ++ * Parse a string containing a 32-bit unsigned integer. ++ * Returns the number of chars used, or zero if no number is found. ++ */ ++#ifdef NF_NEED_STRTOU32 ++static int ++nf_strtou32(const char* pbuf, u_int32_t* pval) ++{ ++ int n = 0; ++ ++ *pval = 0; ++ while (pbuf[n] >= '0' && pbuf[n] <= '9') ++ { ++ *pval = (*pval * 10) + (pbuf[n] - '0'); ++ n++; ++ } ++ ++ return n; ++} ++#endif /* NF_NEED_STRTOU32 */ ++ ++/* ++ * Given a buffer and length, advance to the next line and mark the current ++ * line. ++ */ ++#ifdef NF_NEED_NEXTLINE ++static int ++nf_nextline(char* p, uint len, uint* poff, uint* plineoff, uint* plinelen) ++{ ++ uint off = *poff; ++ uint physlen = 0; ++ ++ if (off >= len) ++ { ++ return 0; ++ } ++ ++ while (p[off] != '\n') ++ { ++ if (len-off <= 1) ++ { ++ return 0; ++ } ++ ++ physlen++; ++ off++; ++ } ++ ++ /* if we saw a crlf, physlen needs adjusted */ ++ if (physlen > 0 && p[off] == '\n' && p[off-1] == '\r') ++ { ++ physlen--; ++ } ++ ++ /* advance past the newline */ ++ off++; ++ ++ *plineoff = *poff; ++ *plinelen = physlen; ++ *poff = off; ++ ++ return 1; ++} ++#endif /* NF_NEED_NEXTLINE */ ++ ++#endif /* __KERNEL__ */ ++ ++#endif /* _NETFILTER_HELPERS_H */ +diff -urN linux-2.4.30/include/linux/netfilter_mime.h linux-2.4.30.new/include/linux/netfilter_mime.h +--- linux-2.4.30/include/linux/netfilter_mime.h 1970-01-01 01:00:00.000000000 +0100 ++++ linux-2.4.30.new/include/linux/netfilter_mime.h 2006-02-07 15:46:07.000000000 +0100 +@@ -0,0 +1,90 @@ ++/* ++ * MIME functions for netfilter modules. This file provides implementations ++ * for basic MIME parsing. MIME headers are used in many protocols, such as ++ * HTTP, RTSP, SIP, etc. ++ * ++ * gcc will warn for defined but unused functions, so we only include the ++ * functions requested. The following macros are used: ++ * NF_NEED_MIME_NEXTLINE nf_mime_nextline() ++ */ ++#ifndef _NETFILTER_MIME_H ++#define _NETFILTER_MIME_H ++ ++/* Only include these functions for kernel code. */ ++#ifdef __KERNEL__ ++ ++#include ++#include ++ ++/* ++ * Given a buffer and length, advance to the next line and mark the current ++ * line. If the current line is empty, *plinelen will be set to zero. If ++ * not, it will be set to the actual line length (including CRLF). ++ * ++ * 'line' in this context means logical line (includes LWS continuations). ++ * Returns 1 on success, 0 on failure. ++ */ ++#ifdef NF_NEED_MIME_NEXTLINE ++static int ++nf_mime_nextline(char* p, uint len, uint* poff, uint* plineoff, uint* plinelen) ++{ ++ uint off = *poff; ++ uint physlen = 0; ++ int is_first_line = 1; ++ ++ if (off >= len) ++ { ++ return 0; ++ } ++ ++ do ++ { ++ while (p[off] != '\n') ++ { ++ if (len-off <= 1) ++ { ++ return 0; ++ } ++ ++ physlen++; ++ off++; ++ } ++ ++ /* if we saw a crlf, physlen needs adjusted */ ++ if (physlen > 0 && p[off] == '\n' && p[off-1] == '\r') ++ { ++ physlen--; ++ } ++ ++ /* advance past the newline */ ++ off++; ++ ++ /* check for an empty line */ ++ if (physlen == 0) ++ { ++ break; ++ } ++ ++ /* check for colon on the first physical line */ ++ if (is_first_line) ++ { ++ is_first_line = 0; ++ if (memchr(p+(*poff), ':', physlen) == NULL) ++ { ++ return 0; ++ } ++ } ++ } ++ while (p[off] == ' ' || p[off] == '\t'); ++ ++ *plineoff = *poff; ++ *plinelen = (physlen == 0) ? 0 : (off - *poff); ++ *poff = off; ++ ++ return 1; ++} ++#endif /* NF_NEED_MIME_NEXTLINE */ ++ ++#endif /* __KERNEL__ */ ++ ++#endif /* _NETFILTER_MIME_H */ diff --git a/openwrt/target/linux/netfilter.mk b/openwrt/target/linux/netfilter.mk index 08c104ea75..711190cf22 100644 --- a/openwrt/target/linux/netfilter.mk +++ b/openwrt/target/linux/netfilter.mk @@ -59,6 +59,12 @@ IPKG_KMOD_IPT_NAT_EXTRA-$(CONFIG_IP_NF_NAT_PPTP) += ip_nat_pptp IPKG_KMOD_IPT_NAT_EXTRA-$(CONFIG_IP_NF_NAT_SNMP_BASIC) += ip_nat_snmp_basic IPKG_KMOD_IPT_NAT_EXTRA-$(CONFIG_IP_NF_TFTP) += ip_conntrack_tftp IPKG_KMOD_IPT_NAT_EXTRA-$(CONFIG_IP_NF_NAT_TFTP) += ip_nat_tftp +IPKG_KMOD_IPT_NAT_EXTRA-$(CONFIG_IP_NF_SIP) += ip_conntrack_sip +IPKG_KMOD_IPT_NAT_EXTRA-$(CONFIG_IP_NF_NAT_SIP) += ip_nat_sip +IPKG_KMOD_IPT_NAT_EXTRA-$(CONFIG_IP_NF_H323) += ip_conntrack_h323 +IPKG_KMOD_IPT_NAT_EXTRA-$(CONFIG_IP_NF_NAT_H323) += ip_nat_h323 +IPKG_KMOD_IPT_NAT_EXTRA-$(CONFIG_IP_NF_RTSP) += ip_conntrack_rtsp +IPKG_KMOD_IPT_NAT_EXTRA-$(CONFIG_IP_NF_NAT_RTSP) += ip_nat_rtsp IPKG_KMOD_IPT_QUEUE-m := IPKG_KMOD_IPT_QUEUE-$(CONFIG_IP_NF_QUEUE) += ip_queue -- 2.30.2